Collaborators: Shane Blowes, Jon Chase, Helmut Hillebrand, Michael Burrows, Amanda Bates, Uli Brose, Benoit Gauzens, Laura Antao Assistance: Katherine Lew, Josef Hauser

Introduction

Methods

library(data.table) # for handling large datasets
library(ggplot2) # for some plotting
#library(lme4)
library(nlme) # for ME models
library(beanplot) # for beanplots
library(maps) # for map
library(ggeffects) # marginal effect plots
library(gridExtra) # to combine ggplots together
library(grid) # to combine ggplots together
library(gridExtra)

options(width=500) # turn off most text wrapping

# tell RStudio to use project root directory as the root for this notebook. Needed since we are storing code in a separate directory.
knitr::opts_knit$set(root.dir = rprojroot::find_rstudio_root_file()) 
# Turnover and covariates assembled by turnover_vs_temperature_prep.Rmd
trends <- fread('output/turnover_w_covariates.csv.gz')

# set realm order
trends[, REALM := factor(REALM, levels = c('Freshwater', 'Marine', 'Terrestrial'), ordered = FALSE)]

# group Marine invertebrates/plants in with All
trends[, taxa_mod2 := taxa_mod]
trends[taxa_mod == 'Marine invertebrates/plants', taxa_mod2 := 'All']

Log-transform some variables, then center and scale.

trends[, tempave.sc := scale(tempave)]
trends[, tempave_metab.sc := scale(tempave_metab)]
trends[, seas.sc := scale(seas)]
trends[, microclim.sc := scale(log(microclim))]
trends[, temptrend.sc := scale(temptrend)]
trends[, temptrend_abs.sc := scale(log(abs(temptrend)))]
trends[, npp.sc := scale(log(npp))]
trends[, mass.sc := scale(log(mass_mean_weight))]
trends[, speed.sc := scale(log(speed_mean_weight+1))]
trends[, lifespan.sc := scale(log(lifespan_mean_weight))]
trends[, thermal_bias.sc := scale(thermal_bias)]
trends[, consumerfrac.sc := scale(consfrac)]
trends[, endothermfrac.sc := scale(endofrac)]
trends[, nspp.sc := scale(log(Nspp))]
trends[, human.sc := scale(human)]

Do the variables look ok?

# histograms to examine
cexmain = 0.6
par(mfrow = c(3,5))
invisible(trends[, hist(tempave.sc, main = 'Environmental temperature (°C)', cex.main = cexmain)])
invisible(trends[, hist(tempave_metab.sc, main = 'Metabolic temperature (°C)', cex.main = cexmain)])
invisible(trends[, hist(seas.sc, main = 'Seasonality (°C)', cex.main = cexmain)])
invisible(trends[, hist(microclim.sc, main = 'log Microclimates (°C)', cex.main = cexmain)])
invisible(trends[, hist(temptrend.sc, main = 'Temperature trend (°C/yr)', cex.main = cexmain)])
invisible(trends[, hist(temptrend_abs.sc, main = 'log abs(Temperature trend) (°C/yr)', cex.main = cexmain)])
invisible(trends[, hist(mass.sc, main = 'log Mass (g)', cex.main = cexmain)])
invisible(trends[, hist(speed.sc, main = 'log Speed (km/hr)', cex.main = cexmain)])
invisible(trends[, hist(lifespan.sc, main = 'log Lifespan (yr)', cex.main = cexmain)])
invisible(trends[, hist(consumerfrac.sc, main = 'Consumers (fraction)', cex.main = cexmain)])
invisible(trends[, hist(endothermfrac.sc, main = 'Endotherms (fraction)', cex.main = cexmain)])
invisible(trends[, hist(nspp.sc, main = 'log Species richness', cex.main = cexmain)])
invisible(trends[, hist(thermal_bias.sc, main = 'Thermal bias (°C)', cex.main = cexmain)])
invisible(trends[, hist(npp.sc, main = 'log Net primary productivity', cex.main = cexmain)])
invisible(trends[, hist(human.sc, main = 'Human impact score', cex.main = cexmain)])

Check correlations among variables. Pearson’s r is on the lower diagonal.

panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...)
{
    usr <- par("usr"); on.exit(par(usr))
    par(usr = c(0, 1, 0, 1))
    r <- cor(x, y, use = 'pairwise.complete.obs')
    txt <- format(c(r, 0.123456789), digits = digits)[1]
    txt <- paste0(prefix, txt)
    if(missing(cex.cor)) cex.cor <- 0.8/strwidth(txt)
    text(0.5, 0.5, txt) #, cex = cex.cor * r)
}
pairs(formula = ~ REALM + tempave.sc + tempave_metab.sc + seas.sc + microclim.sc + temptrend.sc + temptrend_abs.sc +  mass.sc + speed.sc + lifespan.sc + consumerfrac.sc + endothermfrac.sc + nspp.sc + thermal_bias.sc + npp.sc + human.sc, data = trends, gap = 1/10, cex = 0.2, col = '#00000022', lower.panel = panel.cor)

Mass and lifespan look tightly correlated, but r only 0.56…? Tempave_metab and lifespan don’t look tightly correlated, but r= -0.81 Tempave_metab and speed don’t look tightly correlated, but r= -0.83 Lifespan and speed don’t look tightly correlated, but r = 0.73

Examine how many data points are available

Just turnover

cat('Overall # time-series: ', nrow(trends), '\n')
Overall # time-series:  53013 
cat('# studies: ', trends[, length(unique(STUDY_ID))], '\n')
# studies:  332 
cat('Data points: ', trends[, sum(nyrBT)], '\n')
Data points:  293973 
trends[, table(REALM)]
REALM
 Freshwater      Marine Terrestrial 
       1025       48647        3341 
trends[, table(taxa_mod)]
taxa_mod
                        All                  Amphibians                     Benthos                       Birds 
                       1705                         379                        4679                       13741 
                       Fish               Invertebrates                     Mammals Marine invertebrates/plants 
                      28473                        2996                         525                         206 
                      Plant                    Reptiles 
                        305                           4 
trends[, table(taxa_mod, REALM)]
                             REALM
taxa_mod                      Freshwater Marine Terrestrial
  All                                  0   1702           3
  Amphibians                           2      0         377
  Benthos                              0   4679           0
  Birds                                0  11099        2642
  Fish                              1006  27467           0
  Invertebrates                       15   2901          80
  Mammals                              0    478          47
  Marine invertebrates/plants          0    206           0
  Plant                                1    115         189
  Reptiles                             1      0           3

With all covariates

# the cases we can compare
apply(trends[, .(Jtutrend, REALM, tempave.sc, tempave_metab.sc, seas.sc, microclim.sc, temptrend.sc, mass.sc, speed.sc, lifespan.sc, consumerfrac.sc, endothermfrac.sc, nspp.sc, thermal_bias.sc, npp.sc, human.sc)], MARGIN = 2, FUN = function(x) sum(!is.na(x)))
        Jtutrend            REALM       tempave.sc tempave_metab.sc          seas.sc     microclim.sc 
           53013            53013            49916            49916            49916            51834 
    temptrend.sc          mass.sc         speed.sc      lifespan.sc  consumerfrac.sc endothermfrac.sc 
           49916            52820            52689            51540            47534            53013 
         nspp.sc  thermal_bias.sc           npp.sc         human.sc 
           53013            49371            52863            53013 
i <- trends[, complete.cases(Jtutrend, temptrend.sc, tempave_metab.sc, REALM, seas.sc, microclim.sc, npp.sc, mass.sc, speed.sc, lifespan.sc, consumerfrac.sc, thermal_bias.sc)]
cat('Overall # time-series: ', sum(i), '\n')
Overall # time-series:  43585 
cat('# studies: ', trends[i, length(unique(STUDY_ID))], '\n')
# studies:  250 
cat('Data points: ', trends[i, sum(nyrBT)], '\n')
Data points:  222824 
trends[i, table(REALM)]
REALM
 Freshwater      Marine Terrestrial 
       1008       39735        2842 
trends[i, table(taxa_mod)]
taxa_mod
          All    Amphibians       Benthos         Birds          Fish Invertebrates       Mammals         Plant 
          521            12           590         11803         27372          2567           518           200 
     Reptiles 
            2 
trends[i, table(taxa_mod, REALM)]
               REALM
taxa_mod        Freshwater Marine Terrestrial
  All                    0    520           1
  Amphibians             2      0          10
  Benthos                0    590           0
  Birds                  0   9221        2582
  Fish                 993  26379           0
  Invertebrates         12   2484          71
  Mammals                0    477          41
  Plant                  1     64         135
  Reptiles               0      0           2

Choose the variance structure for mixed effects modles

Try combinations of

  • variance scaled to a power of the number of years in the community time-series
  • variance scaled to a power of the abs temperature trend
  • random intercept for taxa_mod
  • random intercept for STUDY_ID
  • random slope (abs temperature trend) for taxa_mod
  • random slope (abs temperature trend) for STUDY_ID
  • random intercept for rarefyID (for overdispersion)

And choose the one with lowest AIC (not run: takes a long time)

# fit models for variance structure
fixed <- formula(Jtutrend ~ REALM + tempave_metab.sc + seas.sc + microclim.sc + npp.sc + temptrend_abs.sc +
                     mass.sc + speed.sc + lifespan.sc + consumerfrac.sc + thermal_bias.sc)
i <- trends[, complete.cases(Jtutrend, REALM, tempave_metab.sc, seas.sc, microclim.sc, npp.sc, temptrend_abs.sc,
                             mass.sc, speed.sc, lifespan.sc, consumerfrac.sc, thermal_bias.sc)]
mods <- vector('list', 0)
mods[[1]] <- gls(fixed, data = trends[i,])
mods[[2]] <- gls(fixed, data = trends[i,], weights = varPower(-0.5, ~nyrBT))
mods[[3]] <- gls(fixed, data = trends[i,], weights = varPower(0.5, ~ abs(temptrend)))

mods[[4]] <- lme(fixed, data = trends[i,], random = ~1|taxa_mod2, control = lmeControl(opt = "optim"))
mods[[5]] <- lme(fixed, data = trends[i,], random = ~1|STUDY_ID, control = lmeControl(opt = "optim"))
mods[[6]] <- lme(fixed, data = trends[i,], random = ~1|taxa_mod2/STUDY_ID, control = lmeControl(opt = "optim"))
mods[[7]] <- lme(fixed, data = trends[i,], random = ~1|STUDY_ID/rarefyID, control = lmeControl(opt = "optim"))
mods[[8]] <- lme(fixed, data = trends[i,], random = ~1|taxa_mod2/STUDY_ID/rarefyID, control = lmeControl(opt = "optim"))

mods[[9]] <- lme(fixed, data = trends[i,], random = ~temptrend_abs.sc | taxa_mod)
mods[[10]] <- lme(fixed, data = trends[i,], random = ~temptrend_abs.sc | STUDY_ID)
mods[[11]] <- lme(fixed, data = trends[i,], random = ~temptrend_abs.sc | taxa_mod2/STUDY_ID, control = lmeControl(opt = "optim"))
mods[[12]] <- lme(fixed, data = trends[i,], random = list(STUDY_ID = ~ temptrend_abs.sc, rarefyID = ~1)) # includes overdispersion. new formula so that random slope is only for study level (not enough data to extend to rarefyID).
mods[[13]] <- lme(fixed, data = trends[i,], random = list(taxa_mod2 = ~ temptrend_abs.sc, STUDY_ID = ~ temptrend_abs.sc, rarefyID = ~1)) # 30+ min to fit

mods[[14]] <- lme(fixed, data = trends[i,], random = ~1|STUDY_ID, weights = varPower(-0.5, ~nyrBT))
mods[[15]] <- lme(fixed, data = trends[i,], random = ~1|taxa_mod2, weights = varPower(-0.5, ~nyrBT))
mods[[16]] <- lme(fixed, data = trends[i,], random = ~1|taxa_mod2/STUDY_ID, weights = varPower(-0.5, ~nyrBT))
mods[[17]] <- lme(fixed, data = trends[i,], random = ~1|STUDY_ID/rarefyID, weights = varPower(-0.5, ~nyrBT))
mods[[18]] <- lme(fixed, data = trends[i,], random = ~1|taxa_mod2/STUDY_ID/rarefyID, weights = varPower(-0.5, ~nyrBT))
mods[[19]] <- lme(fixed, data = trends[i,], random = ~temptrend_abs.sc|STUDY_ID, weights = varPower(-0.5, ~nyrBT))
mods[[20]] <- lme(fixed, data = trends[i,], random = list(STUDY_ID = ~ temptrend_abs.sc, rarefyID = ~1), weights = varPower(-0.5, ~nyrBT))
mods[[21]] <- lme(fixed, data = trends[i,], random = list(taxa_mod2 = ~ temptrend_abs.sc, STUDY_ID = ~ 1), weights = varPower(-0.5, ~nyrBT))
mods[[22]] <- lme(fixed, data = trends[i,], random = list(taxa_mod2 = ~ temptrend_abs.sc, STUDY_ID = ~ 1, rarefyID = ~1), weights = varPower(-0.5, ~nyrBT))
mods[[23]] <- lme(fixed, data = trends[i,], random = list(taxa_mod2 = ~ temptrend_abs.sc, STUDY_ID = ~ temptrend_abs.sc), weights = varPower(-0.5, ~nyrBT)) # singular precision warning with lmeControl(opt = 'optim') and convergence error without
mods[[24]] <- lme(fixed, data = trends[i,], random = list(taxa_mod2 = ~ temptrend_abs.sc, STUDY_ID = ~ temptrend_abs.sc, rarefyID = ~1), weights = varPower(-0.5, ~nyrBT)) # singular precision warning with lmeControl(opt = 'optim') and convergence error without

mods[[25]] <- lme(fixed, data = trends[i,], random = ~1|taxa_mod2, weights = varPower(-0.5, ~abs(temptrend)))
mods[[26]] <- lme(fixed, data = trends[i,], random = ~1|STUDY_ID, weights = varPower(-0.5, ~abs(temptrend)))
mods[[27]] <- lme(fixed, data = trends[i,], random = ~1|STUDY_ID/rarefyID, weights = varPower(-0.5, ~abs(temptrend)))
mods[[28]] <- lme(fixed, data = trends[i,], random = ~1|taxa_mod2/STUDY_ID/rarefyID, weights = varPower(-0.5, ~abs(temptrend)))
mods[[29]] <- lme(fixed, data = trends[i,], random = ~temptrend_abs.sc|STUDY_ID, weights = varPower(-0.5, ~abs(temptrend)))
mods[[30]] <- lme(fixed, data = trends[i,], random = ~temptrend_abs.sc|taxa_mod2/STUDY_ID, weights = varPower(-0.5, ~abs(temptrend)), control = lmeControl(opt = "optim"))
mods[[31]] <- lme(fixed, data = trends[i,], random = list(STUDY_ID = ~ temptrend_abs.sc, rarefyID = ~1), weights = varPower(-0.5, ~abs(temptrend)))
mods[[32]] <- lme(fixed, data = trends[i,], random = list(taxa_mod2 = ~ temptrend_abs.sc, STUDY_ID = ~ temptrend_abs.sc, rarefyID = ~1), weights = varPower(-0.5, ~abs(temptrend)), control = lmeControl(opt = "optim")) # singular precision warning

aics <- sapply(mods, AIC)
minaics <- aics - min(aics)
minaics
which.min(aics)

Chooses the random slopes (temptrend_abs) & intercepts for STUDY_ID, overdispersion, and variance scaled to number of years. We haven’t dealt with potential testing on the boundary issues here yet.

Results

Where do we have data?

world <- map_data('world')
ggplot(world, aes(x = long, y = lat, group = group)) +
    geom_polygon(fill = 'lightgray', color = 'white') +
    geom_point(data = trends, aes(rarefyID_x, rarefyID_y, group = REALM, color = REALM), size = 0.5, alpha = 0.4)  +
    scale_color_brewer(palette="Set1", name = 'Realm') +
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        panel.background = element_blank(), axis.line = element_line(colour = "black"),
        legend.key=element_blank(),
        axis.text=element_text(size=16),
        axis.title=element_text(size=20)) +
  labs(x = 'Longitude (°)', y = 'Latitude (°)')

Mostly northern hemisphere, but spread all over. No so much in Africa or much of Asia.

Plot turnover vs. explanatory variables

Lines are ggplot smoother fits by realm.

Strong trends with temperature change, but trends are pretty symmetric around no trend in temperature, which implies warming or cooling drives similar degree of community turnover. Some indication of less turnover for larger organisms (mass) Higher turnover on land with higher seasonality? More turnover for shorter-lived organisms? No really clear differences among realms.

Nicer plots of turnover vs. temperature?

Violin plots

trends[temptrend <= -0.5, temptrendtext := 'Cooling']
trends[abs(temptrend) <= 0.1, temptrendtext := 'Stable']
trends[temptrend >= 0.5, temptrendtext := 'Warming']

trends[abs(rarefyID_y) < 35, latzone := 'Subtropics']
trends[abs(rarefyID_y) >= 35 & abs(rarefyID_x) < 66.56339, latzone := 'Temperate'] 
trends[abs(rarefyID_y) >= 66.56339, latzone := 'Polar']
trends[, latzone := factor(latzone, levels = c('Subtropics', 'Temperate', 'Polar'))]

p1 <- ggplot(trends, aes(temptrend, Jtutrend, color = REALM, fill = REALM, size = nyrBT)) +
  geom_point(na.rm = TRUE, shape = 16, alpha = 0.1) + 
  geom_smooth(data=subset(trends, abs(temptrend) < 0.75), method = 'gam', formula = y ~ s(x, bs = "cs"), 
              na.rm = TRUE) +
  scale_color_brewer(palette="Set1", name = 'Realm') + 
  scale_fill_brewer(palette="Set1", name = 'Realm') + 
  labs(x = 'Temperature trend (°C/yr)', y = 'Jaccard turnover') +
  scale_size_continuous(range = c(1, 8), breaks = c(2, 5, 20)) +
  guides(size = guide_legend(title = 'Years',
                             override.aes = list(linetype=0, fill = NA, alpha = 1))) +
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        panel.background = element_blank(), axis.line = element_line(colour = "black"),
        legend.key=element_blank(),
        legend.key.size = unit(0.5,"line"), 
        axis.text=element_text(size=8),
        axis.title=element_text(size=10))

p2 <- ggplot(trends[!is.na(temptrendtext), ], aes(temptrendtext, Jtutrend)) +
  geom_violin(draw_quantiles = c(0.25, 0.5, 0.75), fill = 'grey') +
  labs(x = '', y = 'Jaccard turnover') +
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        panel.background = element_blank(), axis.line = element_line(colour = "black"),
        legend.key=element_blank(),
        axis.text=element_text(size=8),
        axis.title=element_text(size=10))

p3 <- ggplot(trends[abs(temptrend) >= 0.5 & !is.na(latzone), ], aes(latzone, Jtutrend)) +
  geom_violin(draw_quantiles = c(0.25, 0.5, 0.75), fill = 'grey') + 
  labs(x = '', y = '') +
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        panel.background = element_blank(), axis.line = element_line(colour = "black"),
        legend.key=element_blank(),
        axis.text=element_text(size=7),
        axis.title=element_text(size=10))

grid.arrange(p1, p2, p3, ncol = 2, layout_matrix = rbind(c(1,1), c(2,3)),
             heights=c(unit(0.66, "npc"), unit(0.34, "npc")))

Average rates of turnover

trends[abs(temptrend) >= 0.5, .(mean(Jtutrend), sd(Jtutrend)/sqrt(.N))] # turnover per year for locations changing temperature
trends[abs(temptrend) < 0.1, .(mean(Jtutrend), sd(Jtutrend)/sqrt(.N))] # not changing temperature
trends[temptrend >= 0.5, .(mean(Jtutrend), sd(Jtutrend)/sqrt(.N))] # warming
trends[temptrend <= -0.5, .(mean(Jtutrend), sd(Jtutrend)/sqrt(.N))] # cooling

trends[abs(temptrend) >= 0.5 & abs(rarefyID_y) < 35, .(mean(Jtutrend), sd(Jtutrend)/sqrt(.N))] # tropics and sub-tropics
trends[abs(temptrend) >= 0.5 & abs(rarefyID_y) >= 35 & abs(rarefyID_y) < 66.56339, .(mean(Jtutrend), sd(Jtutrend)/sqrt(.N))] # temperate
trends[abs(temptrend) >= 0.5 & abs(rarefyID_y) >= 66.56339, .(mean(Jtutrend), sd(Jtutrend)/sqrt(.N))] # arctic

Hexagonal bins

require(ggplot2)
ggplot(trends[REALM == 'Terrestrial',], aes(temptrend, Jtutrend)) +
  geom_hex() + 
  scale_fill_gradient(trans = "log")

ggplot(trends[REALM == 'Marine',], aes(temptrend, Jtutrend)) +
  geom_hex() + 
  scale_fill_gradient(trans = "log")

ggplot(trends[REALM == 'Freshwater',], aes(temptrend, Jtutrend)) +
  geom_hex() + 
  scale_fill_gradient(trans = "log")

Compare covariates across realms

i <- trends[, !duplicated(rarefyID)]; sum(i)
par(mfrow=c(5,3))
beanplot(rarefyID_y ~ REALM, data = trends[i,], what = c(1,1,1,1), col = c("#CAB2D6", "#33A02C", "#B2DF8A"), border = "#CAB2D6", ylab = 'Latitude (degN)', ll = 0.05)
beanplot(tempave ~ REALM, data = trends[i,], what = c(1,1,1,1), col = c("#CAB2D6", "#33A02C", "#B2DF8A"), border = "#CAB2D6", ylab = 'Temperature (degC)', ll = 0.05)
beanplot(tempave_metab ~ REALM, data = trends[i,], what = c(1,1,1,1), col = c("#CAB2D6", "#33A02C", "#B2DF8A"), border = "#CAB2D6", ylab = 'Metabolic Temperature (degC)', ll = 0.05, bw = 'nrd0') # nrd0 bandwidth to calculation gap
beanplot(seas ~ REALM, data = trends[i,], what = c(1,1,1,1), col = c("#CAB2D6", "#33A02C", "#B2DF8A"), border = "#CAB2D6", ylab = 'Seasonality (degC)', ll = 0.05)
beanplot(microclim ~ REALM, data = trends[i,], what = c(1,1,1,1), col = c("#CAB2D6", "#33A02C", "#B2DF8A"), border = "#CAB2D6", ylab = 'Microclimates (degC)', ll = 0.05)
beanplot(temptrend ~ REALM, data = trends[i,], what = c(1,1,1,1), col = c("#CAB2D6", "#33A02C", "#B2DF8A"), border = "#CAB2D6", ylab = 'Temperature trend (degC/yr)', ll = 0.05)
beanplot(mass_mean_weight ~ REALM, data = trends[i,], what = c(1,1,1,1), col = c("#CAB2D6", "#33A02C", "#B2DF8A"), border = "#CAB2D6", ylab = 'Mass (g)', ll = 0.05, log = 'y')
beanplot(speed_mean_weight +1 ~ REALM, data = trends[i,], what = c(1,1,1,1), col = c("#CAB2D6", "#33A02C", "#B2DF8A"), border = "#CAB2D6", ylab = 'Speed (km/hr)', ll = 0.05, log = 'y')
beanplot(lifespan_mean_weight ~ REALM, data = trends[i,], what = c(1,1,1,1), col = c("#CAB2D6", "#33A02C", "#B2DF8A"), border = "#CAB2D6", ylab = 'Lifespan (yr)', ll = 0.05, log = 'y')
#beanplot(consfrac ~ REALM, data = trends[i,], what = c(1,1,1,1), col = c("#CAB2D6", "#33A02C", "#B2DF8A"), border = "#CAB2D6", ylab = 'Consumers (fraction)', ll = 0.05, log = '') # too sparse
#beanplot(endofrac ~ REALM, data = trends[i,], what = c(1,1,1,1), col = c("#CAB2D6", "#33A02C", "#B2DF8A"), border = "#CAB2D6", ylab = 'Endotherms (fraction)', ll = 0.05, log = '') # too sparse
beanplot(Nspp ~ REALM, data = trends[i,], what = c(1,1,1,1), col = c("#CAB2D6", "#33A02C", "#B2DF8A"), border = "#CAB2D6", ylab = 'Number of species', ll = 0.05, log = 'y')
beanplot(thermal_bias ~ REALM, data = trends[i & !is.na(thermal_bias),], what = c(1,1,1,1), col = c("#CAB2D6", "#33A02C", "#B2DF8A"), border = "#CAB2D6", ylab = 'Thermal bias (degC)', ll = 0.05)
beanplot(npp ~ REALM, data = trends[i,], what = c(1,1,1,1), col = c("#CAB2D6", "#33A02C", "#B2DF8A"), border = "#CAB2D6", ylab = 'NPP', ll = 0.05)
beanplot(human ~ REALM, data = trends[i,], what = c(1,1,1,1), col = c("#CAB2D6", "#33A02C", "#B2DF8A"), border = "#CAB2D6", ylab = 'Human impact score', ll = 0.05)

Marine are in generally warmer locations (seawater doesn’t freeze) Marine have much lower seasonality. Marine and freshwater have some very small masses (plankton), but much of dataset is similar to terrestrial. Marine has a lot of slow, crawling organisms, but land has plants. Land also has birds (fast).

Jaccard turnover temporal trend

Try static covariates plus interactions of abs temperature trend with each covariate:

  • realm
  • environmental temperature
  • average metabolic temperature
  • seasonality
  • microclimates
  • NPP
  • speed
  • mass
  • lifespan
  • consumer vs. producer
  • thermal bias

Except for thermal bias: interact with temperature trend (not abs)

Temperature-only model (Jtutrend, Jbetatrend, Horntrend)

summary(modonlyTtrend)
Linear mixed-effects model fit by REML
 Data: trends[i, ] 

Random effects:
 Formula: ~temptrend_abs.sc | STUDY_ID
 Structure: General positive-definite, Log-Cholesky parametrization
                 StdDev     Corr  
(Intercept)      0.04460504 (Intr)
temptrend_abs.sc 0.01904043 0.156 

 Formula: ~1 | rarefyID %in% STUDY_ID
        (Intercept)  Residual
StdDev: 0.001713667 0.2946268

Variance function:
 Structure: Power of variance covariate
 Formula: ~nyrBT 
 Parameter estimates:
   power 
-1.23577 
Fixed effects: Jtutrend ~ abs(temptrend) * REALM 
 Correlation: 
                                (Intr) abs(t) REALMM REALMT a():REALMM
abs(temptrend)                  -0.175                                
REALMMarine                     -0.928  0.162                         
REALMTerrestrial                -0.928  0.162  0.861                  
abs(temptrend):REALMMarine       0.173 -0.990 -0.164 -0.161           
abs(temptrend):REALMTerrestrial  0.172 -0.984 -0.160 -0.166  0.974    

Standardized Within-Group Residuals:
        Min          Q1         Med          Q3         Max 
-8.46254351 -0.30730773  0.08443652  0.54660915  6.61661896 

Number of Observations: 49916
Number of Groups: 
              STUDY_ID rarefyID %in% STUDY_ID 
                   317                  49916 
summary(modonlyTtrendJbeta)
Linear mixed-effects model fit by REML
 Data: trends[i2, ] 

Random effects:
 Formula: ~temptrend_abs.sc | STUDY_ID
 Structure: General positive-definite, Log-Cholesky parametrization
                 StdDev     Corr  
(Intercept)      0.05659393 (Intr)
temptrend_abs.sc 0.02520050 0.021 

 Formula: ~1 | rarefyID %in% STUDY_ID
         (Intercept)  Residual
StdDev: 1.693577e-06 0.3590015

Variance function:
 Structure: Power of variance covariate
 Formula: ~nyrBT 
 Parameter estimates:
    power 
-1.413558 
Fixed effects: Jbetatrend ~ abs(temptrend) * REALM 
 Correlation: 
                                (Intr) abs(t) REALMM REALMT a():REALMM
abs(temptrend)                  -0.160                                
REALMMarine                     -0.928  0.148                         
REALMTerrestrial                -0.931  0.149  0.864                  
abs(temptrend):REALMMarine       0.158 -0.991 -0.150 -0.147           
abs(temptrend):REALMTerrestrial  0.157 -0.986 -0.146 -0.151  0.976    

Standardized Within-Group Residuals:
       Min         Q1        Med         Q3        Max 
-7.8997139 -0.1696297  0.2037637  0.6704994  6.6449583 

Number of Observations: 49916
Number of Groups: 
              STUDY_ID rarefyID %in% STUDY_ID 
                   317                  49916 
summary(modonlyTtrendHorn)
Linear mixed-effects model fit by REML
 Data: trends[i3, ] 

Random effects:
 Formula: ~temptrend_abs.sc | STUDY_ID
 Structure: General positive-definite, Log-Cholesky parametrization
                 StdDev     Corr  
(Intercept)      0.05792109 (Intr)
temptrend_abs.sc 0.02134495 0.134 

 Formula: ~1 | rarefyID %in% STUDY_ID
        (Intercept) Residual
StdDev: 0.007146559 0.306766

Variance function:
 Structure: Power of variance covariate
 Formula: ~nyrBT 
 Parameter estimates:
    power 
-1.217277 
Fixed effects: Horntrend ~ abs(temptrend) * REALM 
 Correlation: 
                                (Intr) abs(t) REALMM REALMT a():REALMM
abs(temptrend)                  -0.154                                
REALMMarine                     -0.914  0.141                         
REALMTerrestrial                -0.925  0.143  0.845                  
abs(temptrend):REALMMarine       0.153 -0.989 -0.142 -0.141           
abs(temptrend):REALMTerrestrial  0.152 -0.984 -0.139 -0.146  0.973    

Standardized Within-Group Residuals:
        Min          Q1         Med          Q3         Max 
-6.16836348 -0.32501087  0.06399723  0.53830958  5.96234033 

Number of Observations: 48800
Number of Groups: 
              STUDY_ID rarefyID %in% STUDY_ID 
                   276                  48800 

Try simplifying the temp-only models

if(file.exists('temp/modonlyTtrendsimpreml.rds')){
  modonlyTtrendsimpreml <- readRDS('temp/modonlyTtrendsimpreml.rds')
} else {
  require(MASS) # for stepAIC
  modonlyTtrendml <- update(modonlyTtrend, method = 'ML')
  modonlyTtrendsimp <- stepAIC(modonlyTtrendml, direction = 'backward')
  modonlyTtrendsimpreml <- update(modonlyTtrendsimp, method = 'REML')
  saveRDS(modonlyTtrendsimpreml, file = 'temp/modonlyTtrendsimpreml.rds')
}


if(file.exists('temp/modonlyTtrendJbetasimpreml.rds')){
  modonlyTtrendJbetasimpreml <- readRDS('temp/modonlyTtrendJbetasimpreml.rds')
} else {
  require(MASS) # for stepAIC
  modonlyTtrendJbetaml <- update(modonlyTtrendJbeta, method = 'ML')
  modonlyTtrendJbetasimp <- stepAIC(modonlyTtrendJbetaml, direction = 'backward')
  modonlyTtrendJbetasimpreml <- update(modonlyTtrendJbetasimp, method = 'REML')
  saveRDS(modonlyTtrendJbetasimpreml, file = 'temp/modonlyTtrendJbetasimpreml.rds')
}
Start:  AIC=-165090
Jbetatrend ~ abs(temptrend) * REALM

                       Df     AIC
<none>                    -165090
- abs(temptrend):REALM  2 -164091
if(file.exists('temp/modonlyTtrendHornsimpreml.rds')){
  modonlyTtrendHornsimpreml <- readRDS('temp/modonlyTtrendHornsimpreml.rds')
} else {
  require(MASS) # for stepAIC
  modonlyTtrendHornml <- update(modonlyTtrendHorn, method = 'ML')
  modonlyTtrendHornsimp <- stepAIC(modonlyTtrendHornml, direction = 'backward')
  modonlyTtrendHornsimpreml <- update(modonlyTtrendHornsimp, method = 'REML')
  saveRDS(modonlyTtrendHornsimpreml, file = 'temp/modonlyTtrendHornsimpreml.rds')
}
Start:  AIC=-146055.2
Horntrend ~ abs(temptrend) * REALM

                       Df     AIC
<none>                    -146055
- abs(temptrend):REALM  2 -145334
summary(modonlyTtrendsimpreml)
Linear mixed-effects model fit by REML
 Data: trends[i, ] 

Random effects:
 Formula: ~temptrend_abs.sc | STUDY_ID
 Structure: General positive-definite, Log-Cholesky parametrization
                 StdDev     Corr  
(Intercept)      0.04460504 (Intr)
temptrend_abs.sc 0.01904043 0.156 

 Formula: ~1 | rarefyID %in% STUDY_ID
        (Intercept)  Residual
StdDev: 0.001713667 0.2946268

Variance function:
 Structure: Power of variance covariate
 Formula: ~nyrBT 
 Parameter estimates:
   power 
-1.23577 
Fixed effects: Jtutrend ~ abs(temptrend) * REALM 
 Correlation: 
                                (Intr) abs(t) REALMM REALMT a():REALMM
abs(temptrend)                  -0.175                                
REALMMarine                     -0.928  0.162                         
REALMTerrestrial                -0.928  0.162  0.861                  
abs(temptrend):REALMMarine       0.173 -0.990 -0.164 -0.161           
abs(temptrend):REALMTerrestrial  0.172 -0.984 -0.160 -0.166  0.974    

Standardized Within-Group Residuals:
        Min          Q1         Med          Q3         Max 
-8.46254351 -0.30730773  0.08443652  0.54660915  6.61661896 

Number of Observations: 49916
Number of Groups: 
              STUDY_ID rarefyID %in% STUDY_ID 
                   317                  49916 
summary(modonlyTtrendJbetasimpreml)
Linear mixed-effects model fit by REML
 Data: trends[i2, ] 

Random effects:
 Formula: ~temptrend_abs.sc | STUDY_ID
 Structure: General positive-definite, Log-Cholesky parametrization
                 StdDev     Corr  
(Intercept)      0.05659393 (Intr)
temptrend_abs.sc 0.02520050 0.021 

 Formula: ~1 | rarefyID %in% STUDY_ID
         (Intercept)  Residual
StdDev: 1.693577e-06 0.3590015

Variance function:
 Structure: Power of variance covariate
 Formula: ~nyrBT 
 Parameter estimates:
    power 
-1.413558 
Fixed effects: Jbetatrend ~ abs(temptrend) * REALM 
 Correlation: 
                                (Intr) abs(t) REALMM REALMT a():REALMM
abs(temptrend)                  -0.160                                
REALMMarine                     -0.928  0.148                         
REALMTerrestrial                -0.931  0.149  0.864                  
abs(temptrend):REALMMarine       0.158 -0.991 -0.150 -0.147           
abs(temptrend):REALMTerrestrial  0.157 -0.986 -0.146 -0.151  0.976    

Standardized Within-Group Residuals:
       Min         Q1        Med         Q3        Max 
-7.8997139 -0.1696297  0.2037637  0.6704994  6.6449583 

Number of Observations: 49916
Number of Groups: 
              STUDY_ID rarefyID %in% STUDY_ID 
                   317                  49916 
summary(modonlyTtrendHornsimpreml)
Linear mixed-effects model fit by REML
 Data: trends[i3, ] 

Random effects:
 Formula: ~temptrend_abs.sc | STUDY_ID
 Structure: General positive-definite, Log-Cholesky parametrization
                 StdDev     Corr  
(Intercept)      0.05792109 (Intr)
temptrend_abs.sc 0.02134495 0.134 

 Formula: ~1 | rarefyID %in% STUDY_ID
        (Intercept) Residual
StdDev: 0.007146559 0.306766

Variance function:
 Structure: Power of variance covariate
 Formula: ~nyrBT 
 Parameter estimates:
    power 
-1.217277 
Fixed effects: Horntrend ~ abs(temptrend) * REALM 
 Correlation: 
                                (Intr) abs(t) REALMM REALMT a():REALMM
abs(temptrend)                  -0.154                                
REALMMarine                     -0.914  0.141                         
REALMTerrestrial                -0.925  0.143  0.845                  
abs(temptrend):REALMMarine       0.153 -0.989 -0.142 -0.141           
abs(temptrend):REALMTerrestrial  0.152 -0.984 -0.139 -0.146  0.973    

Standardized Within-Group Residuals:
        Min          Q1         Med          Q3         Max 
-6.16836348 -0.32501087  0.06399723  0.53830958  5.96234033 

Number of Observations: 48800
Number of Groups: 
              STUDY_ID rarefyID %in% STUDY_ID 
                   276                  48800 

Plot the temp-only coefficients

coefs <- summary(modonlyTtrend)$tTable
coefs2 <- summary(modonlyTtrendJbeta)$tTable
coefs3 <- summary(modonlyTtrendHorn)$tTable

par(las = 1, mai = c(0.8, 2, 0.1, 0.1))
rows1 <- which(grepl('temptrend', rownames(coefs)))
plot(0,0, col = 'white', xlim=c(-0.02, 0.85), ylim = c(1,length(rows1)+0.3), 
     yaxt='n', xlab = 'Turnover per |°C/yr|', ylab ='')
axis(2, at = length(rows1):1, labels = c('Freshwater', 'Marine', 'Terrestrial'), cex.axis = 0.7)
abline(v = 0, col = 'grey')
for(i in 1:length(rows1)){
  x = coefs[rows1[i], 1]
  x2 = coefs2[rows1[i], 1]
  x3 = coefs3[rows1[i], 1]
  if(i>1){ # if an interaction, add the intercept
    x = x + coefs['abs(temptrend)', 1]
    x2 = x2 + coefs2['abs(temptrend)', 1]
    x3 = x3 + coefs3['abs(temptrend)', 1]
  }
  se = coefs[rows1[i], 2]
  se2 = coefs2[rows1[i], 2]
  se3 = coefs3[rows1[i], 2]
  points(x, length(rows1) + 1 - i, pch = 16)
  lines(x = c(x-se, x+se), y = c(length(rows1) + 1 - i, length(rows1) + 1 - i))
  
  points(x2, length(rows1) + 1.1 - i, pch = 16, col = 'light grey')
  lines(x = c(x2-se2, x2+se2), y = c(length(rows1) + 1.1 - i, length(rows1) + 1.1 - i), col = 'light grey')
  
  points(x3, length(rows1) + 1.2 - i, pch = 16, col = 'dark grey')
  lines(x = c(x3-se3, x3+se3), y = c(length(rows1) + 1.2 - i, length(rows1) + 1.2 - i), col = 'dark grey')
}
legend('bottomright', col = c('black', 'dark grey', 'light grey'), lwd = 1, pch = 16, 
       legend = c('Jaccard turnover', 'Jaccard total', 'Horn-Morisita'))

Full model

Try simplifying the model

summary(modTfull1simpreml)
Linear mixed-effects model fit by REML
 Data: trends[i, ] 

Random effects:
 Formula: ~temptrend_abs.sc | STUDY_ID
 Structure: General positive-definite, Log-Cholesky parametrization
                 StdDev     Corr  
(Intercept)      0.05008648 (Intr)
temptrend_abs.sc 0.01884335 0.56  

 Formula: ~1 | rarefyID %in% STUDY_ID
        (Intercept)  Residual
StdDev: 0.001194902 0.3037795

Variance function:
 Structure: Power of variance covariate
 Formula: ~nyrBT 
 Parameter estimates:
    power 
-1.246946 
Fixed effects: Jtutrend ~ temptrend_abs.sc + REALM + tempave.sc + tempave_metab.sc +      seas.sc + microclim.sc + mass.sc + speed.sc + lifespan.sc +      endothermfrac.sc + nspp.sc + temptrend.sc + thermal_bias.sc +      npp.sc + human.sc + temptrend_abs.sc:REALM + temptrend_abs.sc:tempave_metab.sc +      temptrend_abs.sc:seas.sc + temptrend_abs.sc:microclim.sc +      temptrend_abs.sc:mass.sc + temptrend_abs.sc:lifespan.sc +      temptrend_abs.sc:nspp.sc + temptrend.sc:thermal_bias.sc +      temptrend_abs.sc:npp.sc + temptrend_abs.sc:human.sc + REALM:human.sc +      temptrend_abs.sc:REALM:human.sc 
 Correlation: 
                                           (Intr) tmpt_. REALMMr REALMTr tmpv.s tmpv_. ses.sc mcrcl. mss.sc spd.sc
temptrend_abs.sc                            0.360                                                                 
REALMMarine                                -0.918 -0.333                                                          
REALMTerrestrial                           -0.916 -0.325  0.835                                                   
tempave.sc                                  0.004  0.005 -0.014  -0.005                                           
tempave_metab.sc                            0.052  0.023 -0.037  -0.023  -0.289                                   
seas.sc                                    -0.036  0.000  0.053  -0.006   0.268 -0.084                            
microclim.sc                               -0.005  0.007  0.012  -0.016   0.049  0.063  0.171                     
mass.sc                                     0.022  0.000 -0.009  -0.020   0.006 -0.551 -0.045 -0.015              
speed.sc                                    0.013  0.005 -0.025   0.022  -0.003  0.154 -0.072 -0.034 -0.128       
lifespan.sc                                 0.032  0.024 -0.015  -0.006  -0.047  0.750  0.095  0.046 -0.807  0.246
endothermfrac.sc                            0.145  0.007 -0.055  -0.222   0.123 -0.212  0.070  0.017  0.037  0.023
nspp.sc                                    -0.026 -0.009 -0.002  -0.014  -0.042 -0.013 -0.032 -0.053 -0.161 -0.043
temptrend.sc                               -0.006 -0.013  0.006   0.007  -0.050 -0.018 -0.041 -0.014  0.010 -0.009
thermal_bias.sc                             0.035  0.007 -0.047  -0.016   0.760 -0.053 -0.156 -0.135  0.043  0.016
npp.sc                                      0.001 -0.002 -0.003   0.015  -0.322  0.237 -0.255 -0.221 -0.009 -0.032
human.sc                                   -0.167 -0.020  0.157   0.152   0.018 -0.005  0.009  0.017  0.005  0.004
temptrend_abs.sc:REALMMarine               -0.341 -0.955  0.364   0.308   0.000 -0.009  0.011 -0.002  0.004 -0.001
temptrend_abs.sc:REALMTerrestrial          -0.319 -0.896  0.299   0.337  -0.029 -0.021 -0.027 -0.024  0.008 -0.001
temptrend_abs.sc:tempave_metab.sc           0.025  0.081 -0.008  -0.016   0.103  0.365  0.049  0.080 -0.302  0.047
temptrend_abs.sc:seas.sc                    0.019 -0.014 -0.010  -0.039   0.126  0.026  0.222  0.029 -0.029 -0.017
temptrend_abs.sc:microclim.sc              -0.005 -0.036  0.001  -0.001   0.017  0.100  0.060  0.312 -0.036  0.015
temptrend_abs.sc:mass.sc                    0.002 -0.001  0.003  -0.004  -0.008 -0.273 -0.037 -0.025  0.457 -0.030
temptrend_abs.sc:lifespan.sc                0.009  0.050  0.001   0.003  -0.011  0.367  0.050  0.022 -0.385  0.064
temptrend_abs.sc:nspp.sc                   -0.008  0.021 -0.002   0.001  -0.028  0.014  0.001  0.013 -0.070  0.029
temptrend.sc:thermal_bias.sc                0.009  0.019 -0.008  -0.007   0.067  0.033  0.000 -0.032 -0.002  0.008
temptrend_abs.sc:npp.sc                     0.002 -0.054 -0.007   0.012  -0.115  0.095 -0.161 -0.163  0.013  0.000
temptrend_abs.sc:human.sc                  -0.070  0.160  0.066   0.063  -0.004 -0.009  0.005  0.006  0.009 -0.007
REALMMarine:human.sc                        0.167  0.021 -0.158  -0.152  -0.020  0.004 -0.017 -0.024 -0.005 -0.003
REALMTerrestrial:human.sc                   0.166  0.020 -0.157  -0.152  -0.032  0.007 -0.022 -0.006 -0.002 -0.001
temptrend_abs.sc:REALMMarine:human.sc       0.070 -0.158 -0.066  -0.063   0.001  0.009 -0.009 -0.009 -0.009  0.007
temptrend_abs.sc:REALMTerrestrial:human.sc  0.069 -0.160 -0.066  -0.063   0.012  0.007 -0.003 -0.005 -0.008  0.006
                                           lfspn. endth. nspp.s tmptr. thrm_. npp.sc hmn.sc tm_.:REALMM tm_.:REALMT
temptrend_abs.sc                                                                                                   
REALMMarine                                                                                                        
REALMTerrestrial                                                                                                   
tempave.sc                                                                                                         
tempave_metab.sc                                                                                                   
seas.sc                                                                                                            
microclim.sc                                                                                                       
mass.sc                                                                                                            
speed.sc                                                                                                           
lifespan.sc                                                                                                        
endothermfrac.sc                           -0.054                                                                  
nspp.sc                                     0.107  0.051                                                           
temptrend.sc                               -0.007 -0.002  0.013                                                    
thermal_bias.sc                            -0.075  0.028 -0.100  0.003                                             
npp.sc                                      0.053 -0.129 -0.161 -0.013 -0.139                                      
human.sc                                    0.008  0.006 -0.015  0.008  0.015 -0.029                               
temptrend_abs.sc:REALMMarine               -0.011  0.005 -0.003  0.008 -0.003 -0.006  0.020                        
temptrend_abs.sc:REALMTerrestrial          -0.017  0.019  0.000  0.015 -0.023  0.020  0.019  0.855                 
temptrend_abs.sc:tempave_metab.sc           0.385  0.027 -0.011 -0.049  0.108  0.003 -0.001 -0.048      -0.098     
temptrend_abs.sc:seas.sc                    0.035  0.053  0.001 -0.011  0.087 -0.178 -0.003  0.046      -0.082     
temptrend_abs.sc:microclim.sc               0.025 -0.043  0.003  0.000 -0.026 -0.142  0.002  0.044       0.002     
temptrend_abs.sc:mass.sc                   -0.381  0.023 -0.060  0.013  0.017  0.008  0.010  0.011       0.017     
temptrend_abs.sc:lifespan.sc                0.466 -0.031  0.053 -0.010 -0.027  0.011 -0.004 -0.032      -0.038     
temptrend_abs.sc:nspp.sc                    0.076 -0.029  0.303  0.015 -0.051 -0.017 -0.011 -0.053      -0.039     
temptrend.sc:thermal_bias.sc                0.003  0.008 -0.010 -0.402 -0.015 -0.003 -0.006 -0.017      -0.020     
temptrend_abs.sc:npp.sc                     0.010 -0.062 -0.034 -0.016 -0.044  0.366 -0.012  0.040       0.053     
temptrend_abs.sc:human.sc                  -0.008  0.000 -0.003  0.007 -0.008 -0.012  0.409 -0.151      -0.139     
REALMMarine:human.sc                       -0.009 -0.006  0.013 -0.008 -0.014  0.018 -0.998 -0.021      -0.019     
REALMTerrestrial:human.sc                  -0.013 -0.011  0.018 -0.007 -0.020  0.027 -0.998 -0.020      -0.019     
temptrend_abs.sc:REALMMarine:human.sc       0.008  0.000  0.000 -0.006  0.006  0.008 -0.408  0.150       0.139     
temptrend_abs.sc:REALMTerrestrial:human.sc  0.008  0.002  0.004 -0.007  0.011  0.013 -0.406  0.151       0.138     
                                           t_.:_. tmptrnd_bs.sc:s. tmptrnd_bs.sc:mc. tmptrnd_bs.sc:ms.
temptrend_abs.sc                                                                                      
REALMMarine                                                                                           
REALMTerrestrial                                                                                      
tempave.sc                                                                                            
tempave_metab.sc                                                                                      
seas.sc                                                                                               
microclim.sc                                                                                          
mass.sc                                                                                               
speed.sc                                                                                              
lifespan.sc                                                                                           
endothermfrac.sc                                                                                      
nspp.sc                                                                                               
temptrend.sc                                                                                          
thermal_bias.sc                                                                                       
npp.sc                                                                                                
human.sc                                                                                              
temptrend_abs.sc:REALMMarine                                                                          
temptrend_abs.sc:REALMTerrestrial                                                                     
temptrend_abs.sc:tempave_metab.sc                                                                     
temptrend_abs.sc:seas.sc                    0.170                                                     
temptrend_abs.sc:microclim.sc              -0.012  0.058                                              
temptrend_abs.sc:mass.sc                   -0.626 -0.016            0.009                             
temptrend_abs.sc:lifespan.sc                0.829  0.045            0.021            -0.813           
temptrend_abs.sc:nspp.sc                    0.080 -0.056           -0.174            -0.224           
temptrend.sc:thermal_bias.sc                0.072 -0.030           -0.036            -0.004           
temptrend_abs.sc:npp.sc                     0.046 -0.169           -0.213            -0.032           
temptrend_abs.sc:human.sc                  -0.030 -0.018            0.038             0.049           
REALMMarine:human.sc                        0.001 -0.001           -0.005            -0.009           
REALMTerrestrial:human.sc                  -0.001 -0.002            0.001            -0.008           
temptrend_abs.sc:REALMMarine:human.sc       0.030  0.009           -0.037            -0.048           
temptrend_abs.sc:REALMTerrestrial:human.sc  0.023  0.014           -0.027            -0.045           
                                           tmptrnd_bs.sc:l. tmptrnd_bs.sc:ns. tm.:_. tmptrnd_bs.sc:np.
temptrend_abs.sc                                                                                      
REALMMarine                                                                                           
REALMTerrestrial                                                                                      
tempave.sc                                                                                            
tempave_metab.sc                                                                                      
seas.sc                                                                                               
microclim.sc                                                                                          
mass.sc                                                                                               
speed.sc                                                                                              
lifespan.sc                                                                                           
endothermfrac.sc                                                                                      
nspp.sc                                                                                               
temptrend.sc                                                                                          
thermal_bias.sc                                                                                       
npp.sc                                                                                                
human.sc                                                                                              
temptrend_abs.sc:REALMMarine                                                                          
temptrend_abs.sc:REALMTerrestrial                                                                     
temptrend_abs.sc:tempave_metab.sc                                                                     
temptrend_abs.sc:seas.sc                                                                              
temptrend_abs.sc:microclim.sc                                                                         
temptrend_abs.sc:mass.sc                                                                              
temptrend_abs.sc:lifespan.sc                                                                          
temptrend_abs.sc:nspp.sc                    0.231                                                     
temptrend.sc:thermal_bias.sc               -0.004            0.002                                    
temptrend_abs.sc:npp.sc                     0.042           -0.188             0.001                  
temptrend_abs.sc:human.sc                  -0.027           -0.032            -0.004 -0.034           
REALMMarine:human.sc                        0.003            0.010             0.005  0.008           
REALMTerrestrial:human.sc                   0.002            0.013             0.004  0.012           
temptrend_abs.sc:REALMMarine:human.sc       0.027            0.028             0.005  0.024           
temptrend_abs.sc:REALMTerrestrial:human.sc  0.021            0.033             0.006  0.030           
                                           tmptrnd_bs.sc:h. REALMM: REALMT: t_.:REALMM:
temptrend_abs.sc                                                                       
REALMMarine                                                                            
REALMTerrestrial                                                                       
tempave.sc                                                                             
tempave_metab.sc                                                                       
seas.sc                                                                                
microclim.sc                                                                           
mass.sc                                                                                
speed.sc                                                                               
lifespan.sc                                                                            
endothermfrac.sc                                                                       
nspp.sc                                                                                
temptrend.sc                                                                           
thermal_bias.sc                                                                        
npp.sc                                                                                 
human.sc                                                                               
temptrend_abs.sc:REALMMarine                                                           
temptrend_abs.sc:REALMTerrestrial                                                      
temptrend_abs.sc:tempave_metab.sc                                                      
temptrend_abs.sc:seas.sc                                                               
temptrend_abs.sc:microclim.sc                                                          
temptrend_abs.sc:mass.sc                                                               
temptrend_abs.sc:lifespan.sc                                                           
temptrend_abs.sc:nspp.sc                                                               
temptrend.sc:thermal_bias.sc                                                           
temptrend_abs.sc:npp.sc                                                                
temptrend_abs.sc:human.sc                                                              
REALMMarine:human.sc                       -0.408                                      
REALMTerrestrial:human.sc                  -0.408            0.997                     
temptrend_abs.sc:REALMMarine:human.sc      -0.998            0.409   0.407             
temptrend_abs.sc:REALMTerrestrial:human.sc -0.993            0.405   0.404   0.991     

Standardized Within-Group Residuals:
        Min          Q1         Med          Q3         Max 
-7.59387150 -0.34529883  0.05138559  0.55509022  6.91268058 

Number of Observations: 43585
Number of Groups: 
              STUDY_ID rarefyID %in% STUDY_ID 
                   250                  43585 

Plot the coefficients from the simplified model


coefs <- summary(modTfull1simpreml)$tTable
par(las = 1, mai = c(0.5, 3, 0.1, 0.1))
rows1 <- which(!grepl('Intercept', rownames(coefs)))
plot(0,0, col = 'white', xlim=c(-0.02, 0.08), ylim = c(1,length(rows1)), yaxt='n', xlab = '', ylab ='')
axis(2, at = length(rows1):1, labels = rownames(coefs)[rows1], cex.axis = 0.7)
abline(v = 0, col = 'grey')
for(i in 1:length(rows1)){
  x = coefs[rows1[i], 1]
  se = coefs[rows1[i], 2]
  points(x, length(rows1) + 1 - i, pch = 16)
  lines(x = c(x-se, x+se), y = c(length(rows1) + 1 - i, length(rows1) + 1 - i))
}

Plot residuals against each predictor

resids <- resid(modTfull1simpreml)
preds <- getData(modTfull1simpreml)
col = '#00000033'
cex = 0.5
par(mfrow = c(4,4))
boxplot(resids ~ preds$REALM, cex = cex, col = col)
plot(preds$temptrend_abs.sc, resids, cex = cex, col = col)
plot(preds$temptrend.sc, resids, cex = cex, col = col)
plot(preds$tempave.sc, resids, cex = cex, col = col)
plot(preds$tempave_metab.sc, resids, cex = cex, col = col)
plot(preds$seas.sc, resids, cex = cex, col = col)
plot(preds$microclim.sc, resids, cex = cex, col = col)
plot(preds$mass.sc, resids, cex = cex, col = col)
plot(preds$speed.sc, resids, cex = cex, col = col)
plot(preds$lifespan.sc, resids, cex = cex, col = col)
plot(preds$consumerfrac.sc, resids, cex = cex, col = col)
plot(preds$endothermfrac.sc, resids, cex = cex, col = col)
plot(preds$nspp.sc, resids, cex = cex, col = col)
plot(preds$thermal_bias.sc, resids, cex = cex, col = col)
plot(preds$npp.sc, resids, cex = cex, col = col)
plot(preds$human.sc, resids, cex = cex, col = col)

Sensitivity analysis: total turnover and Morisita-Horn models

i2 <- trends[, complete.cases(Jbetatrend, REALM, tempave.sc, tempave_metab.sc, seas.sc, microclim.sc, 
                             temptrend.sc, temptrend_abs.sc, mass.sc, speed.sc, lifespan.sc, 
                             consumerfrac.sc, endothermfrac.sc, nspp.sc, thermal_bias.sc, npp.sc, human.sc)]
i3 <- trends[, complete.cases(Horntrend, REALM, tempave.sc, tempave_metab.sc, seas.sc, microclim.sc, 
                             temptrend.sc, temptrend_abs.sc, mass.sc, speed.sc, lifespan.sc, 
                             consumerfrac.sc, endothermfrac.sc, nspp.sc, thermal_bias.sc, npp.sc, human.sc)]

randef <- list(STUDY_ID = ~ temptrend_abs.sc, rarefyID = ~1)
varef <- varPower(-0.5, ~nyrBT)

# full models
if(file.exists('temp/modTfullJbeta.rds')){
  modTfullJbeta <- readRDS('temp/modTfullJbeta.rds')
} else {
  modTfullJbeta <- lme(Jbetatrend ~ temptrend_abs.sc*REALM + 
                     temptrend_abs.sc*tempave.sc +
                     temptrend_abs.sc*tempave_metab.sc + 
                     temptrend_abs.sc*seas.sc + 
                     temptrend_abs.sc*microclim.sc + 
                     temptrend_abs.sc*mass.sc + 
                     temptrend_abs.sc*speed.sc + 
                     temptrend_abs.sc*lifespan.sc + 
                     temptrend_abs.sc*consumerfrac.sc +
                     temptrend_abs.sc*endothermfrac.sc +
                     temptrend_abs.sc*nspp.sc +
                     temptrend.sc*thermal_bias.sc +
                     temptrend_abs.sc*npp.sc +
                     temptrend_abs.sc*human.sc*REALM,
                   random = randef, weights = varef, data = trends[i2,], method = 'REML')
  saveRDS(modTfullJbeta, file = 'temp/modTfullJbeta.rds')
}

if(file.exists('temp/modTfullHorn.rds')){
  modTfullHorn <- readRDS('temp/modTfullHorn.rds')
} else {
  modTfullHorn <- lme(Horntrend ~ temptrend_abs.sc*REALM + 
                     temptrend_abs.sc*tempave.sc +
                     temptrend_abs.sc*tempave_metab.sc + 
                     temptrend_abs.sc*seas.sc + 
                     temptrend_abs.sc*microclim.sc + 
                     temptrend_abs.sc*mass.sc + 
                     temptrend_abs.sc*speed.sc + 
                     temptrend_abs.sc*lifespan.sc + 
                     temptrend_abs.sc*consumerfrac.sc +
                     temptrend_abs.sc*endothermfrac.sc +
                     temptrend_abs.sc*nspp.sc +
                     temptrend.sc*thermal_bias.sc +
                     temptrend_abs.sc*npp.sc +
                     temptrend_abs.sc*human.sc*REALM,
                   random = randef, weights = varef, data = trends[i3,], method = 'REML')
  saveRDS(modTfullHorn, file = 'temp/modTfullHorn.rds')
}

summary(modTfullJbeta)
summary(modTfullHorn)

# simplify
if(file.exists('temp/modTfullJbetasimp.rds')){
  modTfullJbetasimp <- readRDS('temp/modTfullJbetasimp.rds')
} else {
  require(MASS) # for stepAIC
  modTfullJbetaml <- update(modTfullJbeta, method = 'ML')
  modTfullJbetasimp <- stepAIC(modTfullJbetaml, direction = 'backward')
  saveRDS(modTfullJbetasimp, file = 'temp/modTfullJbetasimp.rds')
}

if(file.exists('temp/modTfullHornsimp.rds')){
  modTfullHornsimp <- readRDS('temp/modTfullHornsimp.rds')
} else {
  require(MASS) # for stepAIC
  modTfullHornml <- update(modTfullHorn, method = 'ML')
  modTfullHornsimp <- stepAIC(modTfullHornml, direction = 'backward')
  saveRDS(modTfullHornsimp, file = 'temp/modTfullHornsimp.rds')
}

summary(modTfullJbetasimp)
summary(modTfullHornsimp)

if(file.exists('temp/modTfullJbetasimpreml.rds')){
  modTfullJbetasimpreml <- readRDS('temp/modTfullJbetasimpreml.rds')
} else {
  modTfullJbetasimpreml <- update(modTfullJbetasimp, method = 'REML')
  saveRDS(modTfullJbetasimpreml, file = 'temp/modTfullJbetasimpreml.rds')
}
if(file.exists('temp/modTfullHornsimpreml.rds')){
  modTfullHornsimpreml <- readRDS('temp/modTfullHornsimpreml.rds')
} else {
  modTfullHornsimpreml <- update(modTfullHornsimp, method = 'REML')
  saveRDS(modTfullHornsimpreml, file = 'temp/modTfullHornsimpreml.rds')
}

# plot coefs
coefs2 <- summary(modTfullJbetasimpreml)$tTable
coefs3 <- summary(modTfullHornsimpreml)$tTable
varstoplot <- unique(c(rownames(coefs2), rownames(coefs3)))

rows1 <- which(!grepl('Intercept|REALM', varstoplot) | grepl(':', varstoplot)) # vars to plot in first graph
rows1_2 <- which(rownames(coefs2) %in% varstoplot[rows1]) # rows in coefs2
rows1_3 <- which(rownames(coefs3) %in% varstoplot[rows1]) # rows in coefs3
xlims1 <- range(c(coefs2[rows1_2,1] - coefs2[rows1_2,2], 
                  coefs2[rows1_2,1] + coefs2[rows1_2,2], 
                  coefs3[rows1_3,1] - coefs3[rows1_3,2], 
                  coefs3[rows1_3,1] + coefs3[rows1_3,2]))

rows2 <- which(grepl('REALM', varstoplot) & !grepl(':', varstoplot)) # vars to plot in 2nd graph
rows2_2 <- which(rownames(coefs2) %in% varstoplot[rows2]) # rows in coefs2
rows2_3 <- which(rownames(coefs3) %in% varstoplot[rows2]) # rows in coefs3
xlims2 <- range(c(coefs2[rows2_2,1] - coefs2[rows2_2,2], 
                  coefs2[rows2_2,1] + coefs2[rows2_2,2], 
                  coefs3[rows2_3,1] - coefs3[rows2_3,2], 
                  coefs3[rows2_3,1] + coefs3[rows2_3,2]))

cols <- c('black', 'grey') # for Jbeta and Horn models, respectively
offs1 <- 0.1 # offset vertically for the two models
offs2 <- 0.01 # offset vertically for the two models (plot 2)

par(mfrow=c(1,2), las = 1, mai = c(0.5, 3, 0.1, 0.1))

plot(0,0, col = 'white', xlim=xlims1, ylim = c(1,length(rows1)), yaxt='n', xlab = '', ylab ='')
axis(2, at = length(rows1):1, labels = varstoplot[rows1], cex.axis = 0.7)
abline(v = 0, col = 'grey')
for(i in 1:length(rows1)){
  if(varstoplot[rows1[i]] %in% rownames(coefs2)){
    x = coefs2[rownames(coefs2) == varstoplot[rows1[i]], 1]
    se = coefs2[rownames(coefs2) == varstoplot[rows1[i]], 2]
    points(x, length(rows1) + 1 - i + offs1, pch = 16, col = cols[1])
    lines(x = c(x-se, x+se), y = c(length(rows1) + 1 - i + offs1, length(rows1) + 1 - i + offs1), col = cols[1])
  }
  if(varstoplot[rows1[i]] %in% rownames(coefs3)){
    x = coefs3[rownames(coefs3) == varstoplot[rows1[i]], 1]
    se = coefs3[rownames(coefs3) == varstoplot[rows1[i]], 2]
    points(x, length(rows1) + 1 - i - offs1, pch = 16, col = cols[2])
    lines(x = c(x-se, x+se), y = c(length(rows1) + 1 - i - offs1, length(rows1) + 1 - i - offs1), col = cols[2])
  }
}

plot(0,0, col = 'white', xlim=xlims2, ylim = c(0.9, length(rows2) + 0.1), yaxt='n', xlab = '', ylab ='')
axis(2, at = length(rows2):1, labels = varstoplot[rows2], cex.axis = 0.7)
abline(v = 0, col = 'grey')
for(i in 1:length(rows2)){
  if(varstoplot[rows2[i]] %in% rownames(coefs2)){
    x = coefs2[rownames(coefs2) == varstoplot[rows2[i]], 1]
    se = coefs2[rownames(coefs2) == varstoplot[rows2[i]], 2]
    points(x, length(rows2) + 1 - i + offs2, pch = 16, col = cols[1])
    lines(x = c(x-se, x+se), y = c(length(rows2) + 1 - i + offs2, length(rows2) + 1 - i + offs2), col = cols[1])
  }
  if(varstoplot[rows2[i]] %in% rownames(coefs3)){
    x = coefs3[rownames(coefs3) == varstoplot[rows2[i]], 1]
    se = coefs3[rownames(coefs3) == varstoplot[rows2[i]], 2]
    points(x, length(rows2) + 1 - i - offs2, pch = 16, col = cols[2])
    lines(x = c(x-se, x+se), y = c(length(rows2) + 1 - i - offs2, length(rows2) + 1 - i - offs2), col = cols[2])
  }
}

Black is for Jaccard total turnover (pres/abs), grey is for Morisita-Horn turnover (considers abundance)

To do

LS0tCnRpdGxlOiAnRHJpdmVycyBvZiB2YXJpYXRpb24gaW4gdGhlIGNvbW11bml0eSByZXNwb25zZSB0byB0ZW1wZXJhdHVyZSBjaGFuZ2UgYWNyb3NzIHJlYWxtcycKc3VidGl0bGU6ICcodXNpbmcgbWl4ZWQgZWZmZWN0cyBtb2RlbHMpJwpvdXRwdXQ6IAogICAgZ2l0aHViX2RvY3VtZW50OiBkZWZhdWx0CiAgICAjaHRtbF9kb2N1bWVudDogZGVmYXVsdAogICAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAotLS0KCkNvbGxhYm9yYXRvcnM6IFNoYW5lIEJsb3dlcywgSm9uIENoYXNlLCBIZWxtdXQgSGlsbGVicmFuZCwgTWljaGFlbCBCdXJyb3dzLCBBbWFuZGEgQmF0ZXMsIFVsaSBCcm9zZSwgQmVub2l0IEdhdXplbnMsIExhdXJhIEFudGFvCkFzc2lzdGFuY2U6IEthdGhlcmluZSBMZXcsIEpvc2VmIEhhdXNlcgoKIyBJbnRyb2R1Y3Rpb24KLSBDbGltYXRlIGNoYW5nZSBpcyBkcml2aW5nIGEgd2lkZXNwcmVhZCByZW9yZ2FuaXphdGlvbiBvZiBlY29sb2dpY2FsIGNvbW11bml0aWVzIGFyb3VuZCB0aGUgd29ybGQgKFBhcm1zZXNhbiAmIFlvaGUgMjAwMywgUG9sb2N6YW5za2EgZXQgYWwuIDIwMTMpLAotIGJ1dCB0aGUgaW1wYWN0cyBvZiBjbGltYXRlIGNoYW5nZSB2YXJ5IHN1YnN0YW50aWFsbHkgZnJvbSBvbmUgbG9jYXRpb24gdG8gYW5vdGhlciBhbmQgYW1vbmcgdGF4YSAoTW9saW5vcyBldCBhbC4gMjAxNiBOQ0MsIEFudGFvIGV0IGFsLiAyMDIwIE5FRSkuCi0gQ29tbXVuaXR5IHJlb3JnYW5pemF0aW9uIGlzIHN1YnN0YW50aWFsbHkgbW9yZSBjb21tb24gdGhhbiBhbiBhZ2dyZWdhdGUgbG9zcyBvciBnYWluIG9mIHNwZWNpZXMgKERvcm5lbGFzIGV0IGFsLiAyMDE0IFNjaWVuY2UsIEJsb3dlcyBldCBhbC4gMjAxOSBTY2llbmNlLCBIaWxsZWJyYW5kIGV0IGFsLiAyMDE3IEogQXBwbCBFY29sKQotIFRoZXJlIGFyZSBtYW55IGh5cG90aGVzZXMgZm9yIHdoeSBzb21lIGNvbW11bml0aWVzIGFyZSBtb3JlIHNlbnNpdGl2ZSB0byB3YXJtaW5nIHRoYW4gb3RoZXJzLCBpbmNsdWRpbmcgZGlmZmVyZW5jZXMgaW4KICAtIG1ldGFib2xpYyByYXRlcyAoRGlsbG9uIGV0IGFsLiAyMDEwIE5hdHVyZSksIAogIC0gdGhlcm1hbCBwaHlzaW9sb2d5IChEZXV0c2NoIGV0IGFsLiAyMDA4IFBOQVMsIFBpbnNreSBldCBhbC4gMjAxOSBOYXR1cmUpLCAKICAtIG1pY3JvY2xpbWF0ZSBhdmFpbGFiaWxpdHkgKEJ1cnJvd3MgZXQgYWwuIDIwMTkgTkNDLCBTdWdnaXR0IGV0IGFsLiAyMDE4IE5DQyksCiAgLSBzcGVjaWVzIG1vYmlsaXR5IChQb2xvY3phbnNrYSBldCBhbC4gMjAxMyBOQ0MsIEJ1cnJvd3MgZXQgYWwuIDIwMTEgU2NpZW5jZSwgU3VuZGF5IGV0IGFsLiAyMDEyIE5DQykKICAtIG9yIGdlbmVyYXRpb24gdGltZSAoQmVhdWdyYW5kIGV0IGFsLiAyMDA5IERTUiBJSSwgUG9sb2N6YW5za2EgZXQgYWwuIDIwMTMgTkNDKSwKICAtIGNvbnN1bWVycyB2cy4gcHJvZHVjZXJzIChQZXRjaGV5IGV0IGFsLiAxOTk5IE5hdHVyZSkKICAtIGNvbW11bml0eSBjb21wb3NpdGlvbiAoU3R1YXJ0LVNtaXRoIGV0IGFsLiAyMDE1IE5hdHVyZSwgQmVhdWdyYW5kIGV0IGEuIDIwMTUgTkNDLCBUcmlzb3MgZXQgYWwuIDIwMjAgTmF0dXJlKSwgCiAgLSBlY29zeXN0ZW0gcHJvZHVjdGl2aXR5IChUaG9tYXMgZXQgYWwuIDIwMTcgR0NCLCBCcmV0dCAxOTcxIEFtIFpvbyksCiAgLSBleHBvc3VyZSB0byBodW1hbiBpbXBhY3RzIChXaGl0ZSAmIEtlcnIgMjAwNiBFY29ncmFwaHkpCiAgLSBhbmQgYW1vbmcgcmVhbG1zIChBbnRhbyBldCBhbC4gMjAyMCBORUUpLgotIFNjYWxpbmcgdXAgZnJvbSBvcmdhbmlzbWFsIGVmZmVjdHMgdG8gd2hvbGUgZWNvbG9naWNhbCBjb21tdW5pdGllcyBpcyBjb21wbGV4LCBhbmQgeWV0IHRoZXNlIHNjYWxlcyBhcmUgY3JpdGljYWwgZm9yIGVjb3N5c3RlbSBmdW5jdGlvbmluZyBhbmQgaHVtYW4gd2VsbC1iZWluZy4gCi0gVGhlcmUgaXMgYSBuZWVkIGZvciBhIGNvbXByZWhlbnNpdmUgdGVzdCB0byB1bmRlcnN0YW5kIHdoZXJlIHdhcm1pbmcgaXMgZHJpdmluZyBhbmQgaXMgbGlrZWx5IHRvIGRyaXZlIHRoZSBtb3N0IGRyYW1hdGljIGNvbW11bml0eSB0dXJub3ZlcgoKIyBNZXRob2RzCi0gQmlvVGltZSBkYXRhc2V0LCBncmlkZGVkIHRvIDk2IGttMiBoZXhhZ29ucywgc3VtbWFyaXplZCBhcyB0ZW1wb3JhbCB0dXJub3ZlciAoQmxvd2VzKQogIC0gVGVtcG9yYWwgc2xvcGUgb2YgSmFjY2FyZCB0dXJub3ZlciBjb21wYXJlZCB0byB0aGUgZmlyc3QgeWVhcgogIC0gU2FtZSBmb3IgSmFjY2FyZCB0b3RhbAogIC0gYW5kIE1vcmlzaXRhLUhvcm4gdHVybm92ZXIKLSBUZXN0ZWQgZXhwbGFuYXRvcnkgdmFyaWFibGVzIGZvciBkaWZmZXJlbmNlcyBpbiByYXRlIG9mIHR1cm5vdmVyOgogIC0gVGVtcGVyYXR1cmUgdHJlbmQgb3ZlciB0aGUgdGltZS1mcmFtZSBvZiBlYWNoIHRpbWUtc2VyaWVzIChDUlUgVFMgNC4wMyBvbiBsYW5kIGFuZCBpbiBmcmVzaHdhdGVyLCBFUlNTVCB2NSBpbiB0aGUgb2NlYW4pCiAgLSBTZWFzb25hbGl0eSBhcyBhIG1ldHJpYyBvZiB0aGVybWFsIHNlbnNpdGl2aXR5IChEZXV0c2NoIGV0IGFsLiAyMDA4IFBOQVMpLiBTdGFuZGFyZCBkZXZpYXRpb24gb2YgbW9udGhseSB0ZW1wZXJhdHVyZXMuCiAgLSBBdmVyYWdlIHRlbXBlcmF0dXJlIGFzIGEgbWV0cmljIG9mIG1ldGFib2xpYyByYXRlcyAoRGlsbG9uIGV0IGFsLiAyMDEwIE5hdHVyZSwgQW50YW8gZXQgYWwuIDIwMjAgTmF0IEUmRSkKICAtIE1vYmlsaXR5IGNhbGN1bGF0ZWQgZnJvbSBib2R5IG1hc3MgYW5kIHRheG9ub21pYyBncm91cCBjbGFzc2lmaWNhdGlvbnMgb2YgbW9iaWxpdHkgbW9kZSAoZmx5LCBydW4sIHN3aW0sIGNyYXdsLCBzZXNzaWxlKS4gRmx5L3J1bi9zd2ltIGZvbGxvd2VkIHRoZSBhbGxvbWV0cmljIHJlbGF0aW9uc2hpcCBpbiBIaXJ0IGV0IGFsLiAyMDE3IE5hdCBFJkUuIENyYXdsIHNldCBhdCAwLjEga20vaHIsIHNlc3NpbGUgc2V0IHRvIDAga20vaHIuIFRoZW4gY2FsY3VsYXRlZCBhdmVyYWdlZCB3aXRoaW4gZWFjaCBhc3NlbWJsYWdlLgogIC0gTmV0IHByaW1hcnkgcHJvZHVjdGl2aXR5IChOUFApIGZyb20gdGhlIG1lcmdlZCBsYW5kL29jZWFuIHByb2R1Y3QgcHJvZHVjZWQgYnkgdGhlIFtPY2VhbiBQcm9kdWN0aXZpdHldKGh0dHA6Ly93d3cuc2NpZW5jZS5vcmVnb25zdGF0ZS5lZHUvb2NlYW4ucHJvZHVjdGl2aXR5LykgZ3JvdXAgYXQgT3JlZ29uIFN0YXRlIHVzaW5nIG1ldGhvZHMgZnJvbSBaaGFvIGV0IGFsLiAyMDA1IGFuZCBCZWhyZW5mZWxkICYgRmFsa293c2tpIDE5OTcuIAogLSBUTyBETzoKICAgLSBHZW5lcmF0aW9uIHRpbWUgY2FsY3VsYXRlZCBmcm9tIGJvZHkgbWFzcyBhbmQgZW5kb3RoZXJtIHZzLiBlY3RvdGhlcm0gY2xhc3NpZmljYXRpb25zLCBmb2xsb3dpbmcgTWNDb3kgJiBHaWxsb29seSAyMDA4IEVMRS4gQXZlcmFnZWQgYWNyb3NzIHNwZWNpZXMgd2l0aGluIGVhY2ggYXNzZW1ibGFnZS4gCiAgIC0gSHVtYW4gaW1wYWN0IGNhbGN1bGF0ZWQgZnJvbSBDYXJzdGVuIE1leWVyJ3MgZWNvc3lzdGVtIGN1YmUgZGF0YQogICAtIFRoZXJtYWwgYmlhcyBjYWxjdWxhdGVkIGZyb20gU3BlY2llcyBUZW1wZXJhdHVyZSBJbmRpY2VzIChNaWtlIEJ1cnJvd3MpCiAgIC0gTWljcm9jbGltYXRlcyBjYWxjdWxhdGVkIGZyb20gV29ybGRDbGltIGFuZCBCaW9PcmFjbGUgKExhdXJhIEFudGFvKQogICAtIENvbnN1bWVyIHZzLiBwcm9kdWNlciBjbGFzc2lmaWNhdGlvbgogLSBNYXliZSB0byBkbzoKICAgLSBTcGVjaWVzIHBvb2wgcmljaG5lc3MKLSBEaWZmZXJlbmNlcyBpbiB0ZW1wb3JhbCB0dXJub3ZlciAocmVzcG9uc2UgdmFyaWFibGUpIG1vZGVsZWQgd2l0aCBhIGxpbmVhciBtaXhlZCBlZmZlY3RzIG1vZGVsIChubG1lIHBhY2thZ2UsIGxtZSgpIGZ1bmN0aW9uKS4gU2VlIGJlbG93IGZvciBkZXRhaWxzLgoKYGBge3Igc2V0dXB9CmxpYnJhcnkoZGF0YS50YWJsZSkgIyBmb3IgaGFuZGxpbmcgbGFyZ2UgZGF0YXNldHMKbGlicmFyeShnZ3Bsb3QyKSAjIGZvciBzb21lIHBsb3R0aW5nCiNsaWJyYXJ5KGxtZTQpCmxpYnJhcnkobmxtZSkgIyBmb3IgTUUgbW9kZWxzCmxpYnJhcnkoYmVhbnBsb3QpICMgZm9yIGJlYW5wbG90cwpsaWJyYXJ5KG1hcHMpICMgZm9yIG1hcApsaWJyYXJ5KGdnZWZmZWN0cykgIyBtYXJnaW5hbCBlZmZlY3QgcGxvdHMKbGlicmFyeShncmlkRXh0cmEpICMgdG8gY29tYmluZSBnZ3Bsb3RzIHRvZ2V0aGVyCmxpYnJhcnkoZ3JpZCkgIyB0byBjb21iaW5lIGdncGxvdHMgdG9nZXRoZXIKbGlicmFyeShncmlkRXh0cmEpCgpvcHRpb25zKHdpZHRoPTUwMCkgIyB0dXJuIG9mZiBtb3N0IHRleHQgd3JhcHBpbmcKCiMgdGVsbCBSU3R1ZGlvIHRvIHVzZSBwcm9qZWN0IHJvb3QgZGlyZWN0b3J5IGFzIHRoZSByb290IGZvciB0aGlzIG5vdGVib29rLiBOZWVkZWQgc2luY2Ugd2UgYXJlIHN0b3JpbmcgY29kZSBpbiBhIHNlcGFyYXRlIGRpcmVjdG9yeS4Ka25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSBycHJvanJvb3Q6OmZpbmRfcnN0dWRpb19yb290X2ZpbGUoKSkgCmBgYAoKYGBge3IgbG9hZCBkYXRhfQojIFR1cm5vdmVyIGFuZCBjb3ZhcmlhdGVzIGFzc2VtYmxlZCBieSB0dXJub3Zlcl92c190ZW1wZXJhdHVyZV9wcmVwLlJtZAp0cmVuZHMgPC0gZnJlYWQoJ291dHB1dC90dXJub3Zlcl93X2NvdmFyaWF0ZXMuY3N2Lmd6JykKCiMgc2V0IHJlYWxtIG9yZGVyCnRyZW5kc1ssIFJFQUxNIDo9IGZhY3RvcihSRUFMTSwgbGV2ZWxzID0gYygnRnJlc2h3YXRlcicsICdNYXJpbmUnLCAnVGVycmVzdHJpYWwnKSwgb3JkZXJlZCA9IEZBTFNFKV0KCiMgZ3JvdXAgTWFyaW5lIGludmVydGVicmF0ZXMvcGxhbnRzIGluIHdpdGggQWxsCnRyZW5kc1ssIHRheGFfbW9kMiA6PSB0YXhhX21vZF0KdHJlbmRzW3RheGFfbW9kID09ICdNYXJpbmUgaW52ZXJ0ZWJyYXRlcy9wbGFudHMnLCB0YXhhX21vZDIgOj0gJ0FsbCddCmBgYAoKTG9nLXRyYW5zZm9ybSBzb21lIHZhcmlhYmxlcywgdGhlbiBjZW50ZXIgYW5kIHNjYWxlLiAKYGBgIHtyIGNlbnRlciBhbmQgc2NhbGV9CnRyZW5kc1ssIHRlbXBhdmUuc2MgOj0gc2NhbGUodGVtcGF2ZSldCnRyZW5kc1ssIHRlbXBhdmVfbWV0YWIuc2MgOj0gc2NhbGUodGVtcGF2ZV9tZXRhYildCnRyZW5kc1ssIHNlYXMuc2MgOj0gc2NhbGUoc2VhcyldCnRyZW5kc1ssIG1pY3JvY2xpbS5zYyA6PSBzY2FsZShsb2cobWljcm9jbGltKSldCnRyZW5kc1ssIHRlbXB0cmVuZC5zYyA6PSBzY2FsZSh0ZW1wdHJlbmQpXQp0cmVuZHNbLCB0ZW1wdHJlbmRfYWJzLnNjIDo9IHNjYWxlKGxvZyhhYnModGVtcHRyZW5kKSkpXQp0cmVuZHNbLCBucHAuc2MgOj0gc2NhbGUobG9nKG5wcCkpXQp0cmVuZHNbLCBtYXNzLnNjIDo9IHNjYWxlKGxvZyhtYXNzX21lYW5fd2VpZ2h0KSldCnRyZW5kc1ssIHNwZWVkLnNjIDo9IHNjYWxlKGxvZyhzcGVlZF9tZWFuX3dlaWdodCsxKSldCnRyZW5kc1ssIGxpZmVzcGFuLnNjIDo9IHNjYWxlKGxvZyhsaWZlc3Bhbl9tZWFuX3dlaWdodCkpXQp0cmVuZHNbLCB0aGVybWFsX2JpYXMuc2MgOj0gc2NhbGUodGhlcm1hbF9iaWFzKV0KdHJlbmRzWywgY29uc3VtZXJmcmFjLnNjIDo9IHNjYWxlKGNvbnNmcmFjKV0KdHJlbmRzWywgZW5kb3RoZXJtZnJhYy5zYyA6PSBzY2FsZShlbmRvZnJhYyldCnRyZW5kc1ssIG5zcHAuc2MgOj0gc2NhbGUobG9nKE5zcHApKV0KdHJlbmRzWywgaHVtYW4uc2MgOj0gc2NhbGUoaHVtYW4pXQpgYGAKCiMjIyBEbyB0aGUgdmFyaWFibGVzIGxvb2sgb2s/CmBgYHtyIGhpc3RvZ3JhbXN9CiMgaGlzdG9ncmFtcyB0byBleGFtaW5lCmNleG1haW4gPSAwLjYKcGFyKG1mcm93ID0gYygzLDUpKQppbnZpc2libGUodHJlbmRzWywgaGlzdCh0ZW1wYXZlLnNjLCBtYWluID0gJ0Vudmlyb25tZW50YWwgdGVtcGVyYXR1cmUgKMKwQyknLCBjZXgubWFpbiA9IGNleG1haW4pXSkKaW52aXNpYmxlKHRyZW5kc1ssIGhpc3QodGVtcGF2ZV9tZXRhYi5zYywgbWFpbiA9ICdNZXRhYm9saWMgdGVtcGVyYXR1cmUgKMKwQyknLCBjZXgubWFpbiA9IGNleG1haW4pXSkKaW52aXNpYmxlKHRyZW5kc1ssIGhpc3Qoc2Vhcy5zYywgbWFpbiA9ICdTZWFzb25hbGl0eSAowrBDKScsIGNleC5tYWluID0gY2V4bWFpbildKQppbnZpc2libGUodHJlbmRzWywgaGlzdChtaWNyb2NsaW0uc2MsIG1haW4gPSAnbG9nIE1pY3JvY2xpbWF0ZXMgKMKwQyknLCBjZXgubWFpbiA9IGNleG1haW4pXSkKaW52aXNpYmxlKHRyZW5kc1ssIGhpc3QodGVtcHRyZW5kLnNjLCBtYWluID0gJ1RlbXBlcmF0dXJlIHRyZW5kICjCsEMveXIpJywgY2V4Lm1haW4gPSBjZXhtYWluKV0pCmludmlzaWJsZSh0cmVuZHNbLCBoaXN0KHRlbXB0cmVuZF9hYnMuc2MsIG1haW4gPSAnbG9nIGFicyhUZW1wZXJhdHVyZSB0cmVuZCkgKMKwQy95ciknLCBjZXgubWFpbiA9IGNleG1haW4pXSkKaW52aXNpYmxlKHRyZW5kc1ssIGhpc3QobWFzcy5zYywgbWFpbiA9ICdsb2cgTWFzcyAoZyknLCBjZXgubWFpbiA9IGNleG1haW4pXSkKaW52aXNpYmxlKHRyZW5kc1ssIGhpc3Qoc3BlZWQuc2MsIG1haW4gPSAnbG9nIFNwZWVkIChrbS9ociknLCBjZXgubWFpbiA9IGNleG1haW4pXSkKaW52aXNpYmxlKHRyZW5kc1ssIGhpc3QobGlmZXNwYW4uc2MsIG1haW4gPSAnbG9nIExpZmVzcGFuICh5ciknLCBjZXgubWFpbiA9IGNleG1haW4pXSkKaW52aXNpYmxlKHRyZW5kc1ssIGhpc3QoY29uc3VtZXJmcmFjLnNjLCBtYWluID0gJ0NvbnN1bWVycyAoZnJhY3Rpb24pJywgY2V4Lm1haW4gPSBjZXhtYWluKV0pCmludmlzaWJsZSh0cmVuZHNbLCBoaXN0KGVuZG90aGVybWZyYWMuc2MsIG1haW4gPSAnRW5kb3RoZXJtcyAoZnJhY3Rpb24pJywgY2V4Lm1haW4gPSBjZXhtYWluKV0pCmludmlzaWJsZSh0cmVuZHNbLCBoaXN0KG5zcHAuc2MsIG1haW4gPSAnbG9nIFNwZWNpZXMgcmljaG5lc3MnLCBjZXgubWFpbiA9IGNleG1haW4pXSkKaW52aXNpYmxlKHRyZW5kc1ssIGhpc3QodGhlcm1hbF9iaWFzLnNjLCBtYWluID0gJ1RoZXJtYWwgYmlhcyAowrBDKScsIGNleC5tYWluID0gY2V4bWFpbildKQppbnZpc2libGUodHJlbmRzWywgaGlzdChucHAuc2MsIG1haW4gPSAnbG9nIE5ldCBwcmltYXJ5IHByb2R1Y3Rpdml0eScsIGNleC5tYWluID0gY2V4bWFpbildKQppbnZpc2libGUodHJlbmRzWywgaGlzdChodW1hbi5zYywgbWFpbiA9ICdIdW1hbiBpbXBhY3Qgc2NvcmUnLCBjZXgubWFpbiA9IGNleG1haW4pXSkKCmBgYAoKIyMjIENoZWNrIGNvcnJlbGF0aW9ucyBhbW9uZyB2YXJpYWJsZXMuIFBlYXJzb24ncyByIGlzIG9uIHRoZSBsb3dlciBkaWFnb25hbC4KYGBge3IgcGFpcnMsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0KcGFuZWwuY29yIDwtIGZ1bmN0aW9uKHgsIHksIGRpZ2l0cyA9IDIsIHByZWZpeCA9ICIiLCBjZXguY29yLCAuLi4pCnsKICAgIHVzciA8LSBwYXIoInVzciIpOyBvbi5leGl0KHBhcih1c3IpKQogICAgcGFyKHVzciA9IGMoMCwgMSwgMCwgMSkpCiAgICByIDwtIGNvcih4LCB5LCB1c2UgPSAncGFpcndpc2UuY29tcGxldGUub2JzJykKICAgIHR4dCA8LSBmb3JtYXQoYyhyLCAwLjEyMzQ1Njc4OSksIGRpZ2l0cyA9IGRpZ2l0cylbMV0KICAgIHR4dCA8LSBwYXN0ZTAocHJlZml4LCB0eHQpCiAgICBpZihtaXNzaW5nKGNleC5jb3IpKSBjZXguY29yIDwtIDAuOC9zdHJ3aWR0aCh0eHQpCiAgICB0ZXh0KDAuNSwgMC41LCB0eHQpICMsIGNleCA9IGNleC5jb3IgKiByKQp9CnBhaXJzKGZvcm11bGEgPSB+IFJFQUxNICsgdGVtcGF2ZS5zYyArIHRlbXBhdmVfbWV0YWIuc2MgKyBzZWFzLnNjICsgbWljcm9jbGltLnNjICsgdGVtcHRyZW5kLnNjICsgdGVtcHRyZW5kX2Ficy5zYyArICBtYXNzLnNjICsgc3BlZWQuc2MgKyBsaWZlc3Bhbi5zYyArIGNvbnN1bWVyZnJhYy5zYyArIGVuZG90aGVybWZyYWMuc2MgKyBuc3BwLnNjICsgdGhlcm1hbF9iaWFzLnNjICsgbnBwLnNjICsgaHVtYW4uc2MsIGRhdGEgPSB0cmVuZHMsIGdhcCA9IDEvMTAsIGNleCA9IDAuMiwgY29sID0gJyMwMDAwMDAyMicsIGxvd2VyLnBhbmVsID0gcGFuZWwuY29yKQoKYGBgCgpNYXNzIGFuZCBsaWZlc3BhbiBsb29rIHRpZ2h0bHkgY29ycmVsYXRlZCwgYnV0IHIgb25seSAwLjU2Li4uPwpUZW1wYXZlX21ldGFiIGFuZCBsaWZlc3BhbiBkb24ndCBsb29rIHRpZ2h0bHkgY29ycmVsYXRlZCwgYnV0IHI9IC0wLjgxIApUZW1wYXZlX21ldGFiIGFuZCBzcGVlZCBkb24ndCBsb29rIHRpZ2h0bHkgY29ycmVsYXRlZCwgYnV0IHI9IC0wLjgzIApMaWZlc3BhbiBhbmQgc3BlZWQgZG9uJ3QgbG9vayB0aWdodGx5IGNvcnJlbGF0ZWQsIGJ1dCByID0gMC43MwoKCiMjIyBFeGFtaW5lIGhvdyBtYW55IGRhdGEgcG9pbnRzIGFyZSBhdmFpbGFibGUKSnVzdCB0dXJub3ZlcgpgYGB7ciBzYW1wbGUgc2l6ZSBhbGx9CmNhdCgnT3ZlcmFsbCAjIHRpbWUtc2VyaWVzOiAnLCBucm93KHRyZW5kcyksICdcbicpCmNhdCgnIyBzdHVkaWVzOiAnLCB0cmVuZHNbLCBsZW5ndGgodW5pcXVlKFNUVURZX0lEKSldLCAnXG4nKQpjYXQoJ0RhdGEgcG9pbnRzOiAnLCB0cmVuZHNbLCBzdW0obnlyQlQpXSwgJ1xuJykKdHJlbmRzWywgdGFibGUoUkVBTE0pXQp0cmVuZHNbLCB0YWJsZSh0YXhhX21vZCldCnRyZW5kc1ssIHRhYmxlKHRheGFfbW9kLCBSRUFMTSldCmBgYAoKV2l0aCBhbGwgY292YXJpYXRlcwpgYGB7ciBzYW1wbGUgc2l6ZSBmb3IgSmFjY2FyZCB0dXJub3Zlcn0KIyB0aGUgY2FzZXMgd2UgY2FuIGNvbXBhcmUKYXBwbHkodHJlbmRzWywgLihKdHV0cmVuZCwgUkVBTE0sIHRlbXBhdmUuc2MsIHRlbXBhdmVfbWV0YWIuc2MsIHNlYXMuc2MsIG1pY3JvY2xpbS5zYywgdGVtcHRyZW5kLnNjLCBtYXNzLnNjLCBzcGVlZC5zYywgbGlmZXNwYW4uc2MsIGNvbnN1bWVyZnJhYy5zYywgZW5kb3RoZXJtZnJhYy5zYywgbnNwcC5zYywgdGhlcm1hbF9iaWFzLnNjLCBucHAuc2MsIGh1bWFuLnNjKV0sIE1BUkdJTiA9IDIsIEZVTiA9IGZ1bmN0aW9uKHgpIHN1bSghaXMubmEoeCkpKQppIDwtIHRyZW5kc1ssIGNvbXBsZXRlLmNhc2VzKEp0dXRyZW5kLCB0ZW1wdHJlbmQuc2MsIHRlbXBhdmVfbWV0YWIuc2MsIFJFQUxNLCBzZWFzLnNjLCBtaWNyb2NsaW0uc2MsIG5wcC5zYywgbWFzcy5zYywgc3BlZWQuc2MsIGxpZmVzcGFuLnNjLCBjb25zdW1lcmZyYWMuc2MsIHRoZXJtYWxfYmlhcy5zYyldCmNhdCgnT3ZlcmFsbCAjIHRpbWUtc2VyaWVzOiAnLCBzdW0oaSksICdcbicpCmNhdCgnIyBzdHVkaWVzOiAnLCB0cmVuZHNbaSwgbGVuZ3RoKHVuaXF1ZShTVFVEWV9JRCkpXSwgJ1xuJykKY2F0KCdEYXRhIHBvaW50czogJywgdHJlbmRzW2ksIHN1bShueXJCVCldLCAnXG4nKQp0cmVuZHNbaSwgdGFibGUoUkVBTE0pXQp0cmVuZHNbaSwgdGFibGUodGF4YV9tb2QpXQp0cmVuZHNbaSwgdGFibGUodGF4YV9tb2QsIFJFQUxNKV0KYGBgCgojIyMgQ2hvb3NlIHRoZSB2YXJpYW5jZSBzdHJ1Y3R1cmUgZm9yIG1peGVkIGVmZmVjdHMgbW9kbGVzClRyeSBjb21iaW5hdGlvbnMgb2YKCi0gdmFyaWFuY2Ugc2NhbGVkIHRvIGEgcG93ZXIgb2YgdGhlIG51bWJlciBvZiB5ZWFycyBpbiB0aGUgY29tbXVuaXR5IHRpbWUtc2VyaWVzCi0gdmFyaWFuY2Ugc2NhbGVkIHRvIGEgcG93ZXIgb2YgdGhlIGFicyB0ZW1wZXJhdHVyZSB0cmVuZAotIHJhbmRvbSBpbnRlcmNlcHQgZm9yIHRheGFfbW9kCi0gcmFuZG9tIGludGVyY2VwdCBmb3IgU1RVRFlfSUQKLSByYW5kb20gc2xvcGUgKGFicyB0ZW1wZXJhdHVyZSB0cmVuZCkgZm9yIHRheGFfbW9kCi0gcmFuZG9tIHNsb3BlIChhYnMgdGVtcGVyYXR1cmUgdHJlbmQpIGZvciBTVFVEWV9JRAotIHJhbmRvbSBpbnRlcmNlcHQgZm9yIHJhcmVmeUlEIChmb3Igb3ZlcmRpc3BlcnNpb24pCgpBbmQgY2hvb3NlIHRoZSBvbmUgd2l0aCBsb3dlc3QgQUlDIChub3QgcnVuOiB0YWtlcyBhIGxvbmcgdGltZSkKYGBge3IgY2hvb3NlIHZhcmlhbmNlIHN0cnVjdHVyZSBmb3IgSmFjYXJkIHR1cm5vdmVyLCBldmFsID0gRkFMU0V9CiMgZml0IG1vZGVscyBmb3IgdmFyaWFuY2Ugc3RydWN0dXJlCmZpeGVkIDwtIGZvcm11bGEoSnR1dHJlbmQgfiBSRUFMTSArIHRlbXBhdmVfbWV0YWIuc2MgKyBzZWFzLnNjICsgbWljcm9jbGltLnNjICsgbnBwLnNjICsgdGVtcHRyZW5kX2Ficy5zYyArCiAgICAgICAgICAgICAgICAgICAgIG1hc3Muc2MgKyBzcGVlZC5zYyArIGxpZmVzcGFuLnNjICsgY29uc3VtZXJmcmFjLnNjICsgdGhlcm1hbF9iaWFzLnNjKQppIDwtIHRyZW5kc1ssIGNvbXBsZXRlLmNhc2VzKEp0dXRyZW5kLCBSRUFMTSwgdGVtcGF2ZV9tZXRhYi5zYywgc2Vhcy5zYywgbWljcm9jbGltLnNjLCBucHAuc2MsIHRlbXB0cmVuZF9hYnMuc2MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFzcy5zYywgc3BlZWQuc2MsIGxpZmVzcGFuLnNjLCBjb25zdW1lcmZyYWMuc2MsIHRoZXJtYWxfYmlhcy5zYyldCm1vZHMgPC0gdmVjdG9yKCdsaXN0JywgMCkKbW9kc1tbMV1dIDwtIGdscyhmaXhlZCwgZGF0YSA9IHRyZW5kc1tpLF0pCm1vZHNbWzJdXSA8LSBnbHMoZml4ZWQsIGRhdGEgPSB0cmVuZHNbaSxdLCB3ZWlnaHRzID0gdmFyUG93ZXIoLTAuNSwgfm55ckJUKSkKbW9kc1tbM11dIDwtIGdscyhmaXhlZCwgZGF0YSA9IHRyZW5kc1tpLF0sIHdlaWdodHMgPSB2YXJQb3dlcigwLjUsIH4gYWJzKHRlbXB0cmVuZCkpKQoKbW9kc1tbNF1dIDwtIGxtZShmaXhlZCwgZGF0YSA9IHRyZW5kc1tpLF0sIHJhbmRvbSA9IH4xfHRheGFfbW9kMiwgY29udHJvbCA9IGxtZUNvbnRyb2wob3B0ID0gIm9wdGltIikpCm1vZHNbWzVdXSA8LSBsbWUoZml4ZWQsIGRhdGEgPSB0cmVuZHNbaSxdLCByYW5kb20gPSB+MXxTVFVEWV9JRCwgY29udHJvbCA9IGxtZUNvbnRyb2wob3B0ID0gIm9wdGltIikpCm1vZHNbWzZdXSA8LSBsbWUoZml4ZWQsIGRhdGEgPSB0cmVuZHNbaSxdLCByYW5kb20gPSB+MXx0YXhhX21vZDIvU1RVRFlfSUQsIGNvbnRyb2wgPSBsbWVDb250cm9sKG9wdCA9ICJvcHRpbSIpKQptb2RzW1s3XV0gPC0gbG1lKGZpeGVkLCBkYXRhID0gdHJlbmRzW2ksXSwgcmFuZG9tID0gfjF8U1RVRFlfSUQvcmFyZWZ5SUQsIGNvbnRyb2wgPSBsbWVDb250cm9sKG9wdCA9ICJvcHRpbSIpKQptb2RzW1s4XV0gPC0gbG1lKGZpeGVkLCBkYXRhID0gdHJlbmRzW2ksXSwgcmFuZG9tID0gfjF8dGF4YV9tb2QyL1NUVURZX0lEL3JhcmVmeUlELCBjb250cm9sID0gbG1lQ29udHJvbChvcHQgPSAib3B0aW0iKSkKCm1vZHNbWzldXSA8LSBsbWUoZml4ZWQsIGRhdGEgPSB0cmVuZHNbaSxdLCByYW5kb20gPSB+dGVtcHRyZW5kX2Ficy5zYyB8IHRheGFfbW9kKQptb2RzW1sxMF1dIDwtIGxtZShmaXhlZCwgZGF0YSA9IHRyZW5kc1tpLF0sIHJhbmRvbSA9IH50ZW1wdHJlbmRfYWJzLnNjIHwgU1RVRFlfSUQpCm1vZHNbWzExXV0gPC0gbG1lKGZpeGVkLCBkYXRhID0gdHJlbmRzW2ksXSwgcmFuZG9tID0gfnRlbXB0cmVuZF9hYnMuc2MgfCB0YXhhX21vZDIvU1RVRFlfSUQsIGNvbnRyb2wgPSBsbWVDb250cm9sKG9wdCA9ICJvcHRpbSIpKQptb2RzW1sxMl1dIDwtIGxtZShmaXhlZCwgZGF0YSA9IHRyZW5kc1tpLF0sIHJhbmRvbSA9IGxpc3QoU1RVRFlfSUQgPSB+IHRlbXB0cmVuZF9hYnMuc2MsIHJhcmVmeUlEID0gfjEpKSAjIGluY2x1ZGVzIG92ZXJkaXNwZXJzaW9uLiBuZXcgZm9ybXVsYSBzbyB0aGF0IHJhbmRvbSBzbG9wZSBpcyBvbmx5IGZvciBzdHVkeSBsZXZlbCAobm90IGVub3VnaCBkYXRhIHRvIGV4dGVuZCB0byByYXJlZnlJRCkuCm1vZHNbWzEzXV0gPC0gbG1lKGZpeGVkLCBkYXRhID0gdHJlbmRzW2ksXSwgcmFuZG9tID0gbGlzdCh0YXhhX21vZDIgPSB+IHRlbXB0cmVuZF9hYnMuc2MsIFNUVURZX0lEID0gfiB0ZW1wdHJlbmRfYWJzLnNjLCByYXJlZnlJRCA9IH4xKSkgIyAzMCsgbWluIHRvIGZpdAoKbW9kc1tbMTRdXSA8LSBsbWUoZml4ZWQsIGRhdGEgPSB0cmVuZHNbaSxdLCByYW5kb20gPSB+MXxTVFVEWV9JRCwgd2VpZ2h0cyA9IHZhclBvd2VyKC0wLjUsIH5ueXJCVCkpCm1vZHNbWzE1XV0gPC0gbG1lKGZpeGVkLCBkYXRhID0gdHJlbmRzW2ksXSwgcmFuZG9tID0gfjF8dGF4YV9tb2QyLCB3ZWlnaHRzID0gdmFyUG93ZXIoLTAuNSwgfm55ckJUKSkKbW9kc1tbMTZdXSA8LSBsbWUoZml4ZWQsIGRhdGEgPSB0cmVuZHNbaSxdLCByYW5kb20gPSB+MXx0YXhhX21vZDIvU1RVRFlfSUQsIHdlaWdodHMgPSB2YXJQb3dlcigtMC41LCB+bnlyQlQpKQptb2RzW1sxN11dIDwtIGxtZShmaXhlZCwgZGF0YSA9IHRyZW5kc1tpLF0sIHJhbmRvbSA9IH4xfFNUVURZX0lEL3JhcmVmeUlELCB3ZWlnaHRzID0gdmFyUG93ZXIoLTAuNSwgfm55ckJUKSkKbW9kc1tbMThdXSA8LSBsbWUoZml4ZWQsIGRhdGEgPSB0cmVuZHNbaSxdLCByYW5kb20gPSB+MXx0YXhhX21vZDIvU1RVRFlfSUQvcmFyZWZ5SUQsIHdlaWdodHMgPSB2YXJQb3dlcigtMC41LCB+bnlyQlQpKQptb2RzW1sxOV1dIDwtIGxtZShmaXhlZCwgZGF0YSA9IHRyZW5kc1tpLF0sIHJhbmRvbSA9IH50ZW1wdHJlbmRfYWJzLnNjfFNUVURZX0lELCB3ZWlnaHRzID0gdmFyUG93ZXIoLTAuNSwgfm55ckJUKSkKbW9kc1tbMjBdXSA8LSBsbWUoZml4ZWQsIGRhdGEgPSB0cmVuZHNbaSxdLCByYW5kb20gPSBsaXN0KFNUVURZX0lEID0gfiB0ZW1wdHJlbmRfYWJzLnNjLCByYXJlZnlJRCA9IH4xKSwgd2VpZ2h0cyA9IHZhclBvd2VyKC0wLjUsIH5ueXJCVCkpCm1vZHNbWzIxXV0gPC0gbG1lKGZpeGVkLCBkYXRhID0gdHJlbmRzW2ksXSwgcmFuZG9tID0gbGlzdCh0YXhhX21vZDIgPSB+IHRlbXB0cmVuZF9hYnMuc2MsIFNUVURZX0lEID0gfiAxKSwgd2VpZ2h0cyA9IHZhclBvd2VyKC0wLjUsIH5ueXJCVCkpCm1vZHNbWzIyXV0gPC0gbG1lKGZpeGVkLCBkYXRhID0gdHJlbmRzW2ksXSwgcmFuZG9tID0gbGlzdCh0YXhhX21vZDIgPSB+IHRlbXB0cmVuZF9hYnMuc2MsIFNUVURZX0lEID0gfiAxLCByYXJlZnlJRCA9IH4xKSwgd2VpZ2h0cyA9IHZhclBvd2VyKC0wLjUsIH5ueXJCVCkpCm1vZHNbWzIzXV0gPC0gbG1lKGZpeGVkLCBkYXRhID0gdHJlbmRzW2ksXSwgcmFuZG9tID0gbGlzdCh0YXhhX21vZDIgPSB+IHRlbXB0cmVuZF9hYnMuc2MsIFNUVURZX0lEID0gfiB0ZW1wdHJlbmRfYWJzLnNjKSwgd2VpZ2h0cyA9IHZhclBvd2VyKC0wLjUsIH5ueXJCVCkpICMgc2luZ3VsYXIgcHJlY2lzaW9uIHdhcm5pbmcgd2l0aCBsbWVDb250cm9sKG9wdCA9ICdvcHRpbScpIGFuZCBjb252ZXJnZW5jZSBlcnJvciB3aXRob3V0Cm1vZHNbWzI0XV0gPC0gbG1lKGZpeGVkLCBkYXRhID0gdHJlbmRzW2ksXSwgcmFuZG9tID0gbGlzdCh0YXhhX21vZDIgPSB+IHRlbXB0cmVuZF9hYnMuc2MsIFNUVURZX0lEID0gfiB0ZW1wdHJlbmRfYWJzLnNjLCByYXJlZnlJRCA9IH4xKSwgd2VpZ2h0cyA9IHZhclBvd2VyKC0wLjUsIH5ueXJCVCkpICMgc2luZ3VsYXIgcHJlY2lzaW9uIHdhcm5pbmcgd2l0aCBsbWVDb250cm9sKG9wdCA9ICdvcHRpbScpIGFuZCBjb252ZXJnZW5jZSBlcnJvciB3aXRob3V0Cgptb2RzW1syNV1dIDwtIGxtZShmaXhlZCwgZGF0YSA9IHRyZW5kc1tpLF0sIHJhbmRvbSA9IH4xfHRheGFfbW9kMiwgd2VpZ2h0cyA9IHZhclBvd2VyKC0wLjUsIH5hYnModGVtcHRyZW5kKSkpCm1vZHNbWzI2XV0gPC0gbG1lKGZpeGVkLCBkYXRhID0gdHJlbmRzW2ksXSwgcmFuZG9tID0gfjF8U1RVRFlfSUQsIHdlaWdodHMgPSB2YXJQb3dlcigtMC41LCB+YWJzKHRlbXB0cmVuZCkpKQptb2RzW1syN11dIDwtIGxtZShmaXhlZCwgZGF0YSA9IHRyZW5kc1tpLF0sIHJhbmRvbSA9IH4xfFNUVURZX0lEL3JhcmVmeUlELCB3ZWlnaHRzID0gdmFyUG93ZXIoLTAuNSwgfmFicyh0ZW1wdHJlbmQpKSkKbW9kc1tbMjhdXSA8LSBsbWUoZml4ZWQsIGRhdGEgPSB0cmVuZHNbaSxdLCByYW5kb20gPSB+MXx0YXhhX21vZDIvU1RVRFlfSUQvcmFyZWZ5SUQsIHdlaWdodHMgPSB2YXJQb3dlcigtMC41LCB+YWJzKHRlbXB0cmVuZCkpKQptb2RzW1syOV1dIDwtIGxtZShmaXhlZCwgZGF0YSA9IHRyZW5kc1tpLF0sIHJhbmRvbSA9IH50ZW1wdHJlbmRfYWJzLnNjfFNUVURZX0lELCB3ZWlnaHRzID0gdmFyUG93ZXIoLTAuNSwgfmFicyh0ZW1wdHJlbmQpKSkKbW9kc1tbMzBdXSA8LSBsbWUoZml4ZWQsIGRhdGEgPSB0cmVuZHNbaSxdLCByYW5kb20gPSB+dGVtcHRyZW5kX2Ficy5zY3x0YXhhX21vZDIvU1RVRFlfSUQsIHdlaWdodHMgPSB2YXJQb3dlcigtMC41LCB+YWJzKHRlbXB0cmVuZCkpLCBjb250cm9sID0gbG1lQ29udHJvbChvcHQgPSAib3B0aW0iKSkKbW9kc1tbMzFdXSA8LSBsbWUoZml4ZWQsIGRhdGEgPSB0cmVuZHNbaSxdLCByYW5kb20gPSBsaXN0KFNUVURZX0lEID0gfiB0ZW1wdHJlbmRfYWJzLnNjLCByYXJlZnlJRCA9IH4xKSwgd2VpZ2h0cyA9IHZhclBvd2VyKC0wLjUsIH5hYnModGVtcHRyZW5kKSkpCm1vZHNbWzMyXV0gPC0gbG1lKGZpeGVkLCBkYXRhID0gdHJlbmRzW2ksXSwgcmFuZG9tID0gbGlzdCh0YXhhX21vZDIgPSB+IHRlbXB0cmVuZF9hYnMuc2MsIFNUVURZX0lEID0gfiB0ZW1wdHJlbmRfYWJzLnNjLCByYXJlZnlJRCA9IH4xKSwgd2VpZ2h0cyA9IHZhclBvd2VyKC0wLjUsIH5hYnModGVtcHRyZW5kKSksIGNvbnRyb2wgPSBsbWVDb250cm9sKG9wdCA9ICJvcHRpbSIpKSAjIHNpbmd1bGFyIHByZWNpc2lvbiB3YXJuaW5nCgphaWNzIDwtIHNhcHBseShtb2RzLCBBSUMpCm1pbmFpY3MgPC0gYWljcyAtIG1pbihhaWNzKQptaW5haWNzCndoaWNoLm1pbihhaWNzKQpgYGAKQ2hvb3NlcyB0aGUgcmFuZG9tIHNsb3BlcyAodGVtcHRyZW5kX2FicykgJiBpbnRlcmNlcHRzIGZvciBTVFVEWV9JRCwgb3ZlcmRpc3BlcnNpb24sIGFuZCB2YXJpYW5jZSBzY2FsZWQgdG8gbnVtYmVyIG9mIHllYXJzLgpXZSBoYXZlbid0IGRlYWx0IHdpdGggcG90ZW50aWFsIHRlc3Rpbmcgb24gdGhlIGJvdW5kYXJ5IGlzc3VlcyBoZXJlIHlldC4KCiMgUmVzdWx0cwojIyBXaGVyZSBkbyB3ZSBoYXZlIGRhdGE/CmBgYHtyIG1hcH0Kd29ybGQgPC0gbWFwX2RhdGEoJ3dvcmxkJykKZ2dwbG90KHdvcmxkLCBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXApKSArCiAgICBnZW9tX3BvbHlnb24oZmlsbCA9ICdsaWdodGdyYXknLCBjb2xvciA9ICd3aGl0ZScpICsKICAgIGdlb21fcG9pbnQoZGF0YSA9IHRyZW5kcywgYWVzKHJhcmVmeUlEX3gsIHJhcmVmeUlEX3ksIGdyb3VwID0gUkVBTE0sIGNvbG9yID0gUkVBTE0pLCBzaXplID0gMC41LCBhbHBoYSA9IDAuNCkgICsKICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJTZXQxIiwgbmFtZSA9ICdSZWFsbScpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBsZWdlbmQua2V5PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTYpLAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjApKSArCiAgbGFicyh4ID0gJ0xvbmdpdHVkZSAowrApJywgeSA9ICdMYXRpdHVkZSAowrApJykKYGBgCgpNb3N0bHkgbm9ydGhlcm4gaGVtaXNwaGVyZSwgYnV0IHNwcmVhZCBhbGwgb3Zlci4gTm8gc28gbXVjaCBpbiBBZnJpY2Egb3IgbXVjaCBvZiBBc2lhLgoKCiMjIFBsb3QgdHVybm92ZXIgdnMuIGV4cGxhbmF0b3J5IHZhcmlhYmxlcwpMaW5lcyBhcmUgZ2dwbG90IHNtb290aGVyIGZpdHMgYnkgcmVhbG0uCmBgYHtyIHBsb3QgdHVybm92ZXIgdiB0ZW1wIHRyZW5kLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0ID0gMTYsIGZpZy53aWR0aCA9IDksfQoKcDEgPC0gZ2dwbG90KHRyZW5kcywgYWVzKFJFQUxNLCBKdHV0cmVuZCkpICsKICBnZW9tX2JveHBsb3QobmEucm0gPSBUUlVFKSArIAogIGxhYnMoeCA9ICdSZWFsbScsIHkgPSAnSmFjY2FyZCB0dXJub3ZlciB0ZW1wb3JhbCB0cmVuZCcpCgpwMiA8LSBnZ3Bsb3QodHJlbmRzLCBhZXModGVtcGF2ZSwgSnR1dHJlbmQsIHNpemUgPSBueXJCVCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IFJFQUxNKSwgc2l6ZSA9IDAuMiwgYWxwaGEgPSAwLjUsIG5hLnJtID0gVFJVRSkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAnZ2FtJywgZm9ybXVsYSA9IHkgfiBzKHgsIGJzID0gImNzIiksIG5hLnJtID0gVFJVRSwgY29sb3IgPSAnYmxhY2snKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGU9IlNldDEiKSArIAogIGxhYnMoeCA9ICdUZW1wZXJhdHVyZSAowrBDKScsIHkgPSAnSmFjY2FyZCB0dXJub3ZlciB0ZW1wb3JhbCB0cmVuZCcpCgpwMyA8LSBnZ3Bsb3QodHJlbmRzLCBhZXModGVtcGF2ZV9tZXRhYiwgSnR1dHJlbmQsIHNpemUgPSBueXJCVCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IFJFQUxNKSwgc2l6ZSA9IDAuMiwgYWxwaGEgPSAwLjUsIG5hLnJtID0gVFJVRSkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAnZ2FtJywgZm9ybXVsYSA9IHkgfiBzKHgsIGJzID0gImNzIiksIG5hLnJtID0gVFJVRSwgY29sb3IgPSAnYmxhY2snKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGU9IlNldDEiKSArIAogIGxhYnMoeCA9ICdNZXRhYm9saWMgdGVtcGVyYXR1cmUgKMKwQyknLCB5ID0gJ0phY2NhcmQgdHVybm92ZXIgdGVtcG9yYWwgdHJlbmQnKQoKcDQgPC0gZ2dwbG90KHRyZW5kcywgYWVzKHNlYXMsIEp0dXRyZW5kLCBzaXplID0gbnlyQlQpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBSRUFMTSksIHNpemUgPSAwLjIsIGFscGhhID0gMC41LCBuYS5ybSA9IFRSVUUpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2dhbScsIGZvcm11bGEgPSB5IH4gcyh4LCBicyA9ICJjcyIpLCBuYS5ybSA9IFRSVUUsIGNvbG9yID0gJ2JsYWNrJykgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJTZXQxIikgKyAKICBsYWJzKHggPSAnU2Vhc29uYWxpdHkgKMKwQyknLCB5ID0gJ0phY2NhcmQgdHVybm92ZXIgdGVtcG9yYWwgdHJlbmQnKQoKcDUgPC0gZ2dwbG90KHRyZW5kcywgYWVzKG1pY3JvY2xpbSwgSnR1dHJlbmQsIHNpemUgPSBueXJCVCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IFJFQUxNKSwgc2l6ZSA9IDAuMiwgYWxwaGEgPSAwLjUsIG5hLnJtID0gVFJVRSkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAnZ2FtJywgZm9ybXVsYSA9IHkgfiBzKHgsIGJzID0gImNzIiksIG5hLnJtID0gVFJVRSwgY29sb3IgPSAnYmxhY2snKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGU9IlNldDEiKSArIAogIHNjYWxlX3hfbG9nMTAoKSArCiAgbGFicyh4ID0gJ01pY3JvY2xpbWF0ZSBhdmFpbGFiaWxpdHkgKMKwQyknLCB5ID0gJ0phY2NhcmQgdHVybm92ZXIgdGVtcG9yYWwgdHJlbmQnKQoKcDYgPC0gZ2dwbG90KHRyZW5kcywgYWVzKG1hc3NfbWVhbl93ZWlnaHQsIEp0dXRyZW5kLCBzaXplID0gbnlyQlQpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBSRUFMTSksIHNpemUgPSAwLjIsIGFscGhhID0gMC41LCBuYS5ybSA9IFRSVUUpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2dhbScsIGZvcm11bGEgPSB5IH4gcyh4LCBicyA9ICJjcyIpLCBuYS5ybSA9IFRSVUUsIGNvbG9yID0gJ2JsYWNrJykgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJTZXQxIikgKyAKICBzY2FsZV94X2xvZzEwKCkgKwogIGxhYnMoeCA9ICdNYXNzIChnKSknLCB5ID0gJ0phY2NhcmQgdHVybm92ZXIgdGVtcG9yYWwgdHJlbmQnKQoKcDcgPC0gZ2dwbG90KHRyZW5kcywgYWVzKHNwZWVkX21lYW5fd2VpZ2h0KzEsIEp0dXRyZW5kLCBzaXplID0gbnlyQlQpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBSRUFMTSksIHNpemUgPSAwLjIsIGFscGhhID0gMC41LCBuYS5ybSA9IFRSVUUpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2dhbScsIGZvcm11bGEgPSB5IH4gcyh4LCBicyA9ICJjcyIpLCBuYS5ybSA9IFRSVUUsIGNvbG9yID0gJ2JsYWNrJykgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJTZXQxIikgKyAKICBzY2FsZV94X2xvZzEwKCkgKwogIGxhYnMoeCA9ICdTcGVlZCAoa20gLyBocikpJywgeSA9ICdKYWNjYXJkIHR1cm5vdmVyIHRlbXBvcmFsIHRyZW5kJykKCnA4IDwtIGdncGxvdCh0cmVuZHMsIGFlcyhsaWZlc3Bhbl9tZWFuX3dlaWdodCwgSnR1dHJlbmQsIHNpemUgPSBueXJCVCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IFJFQUxNKSwgc2l6ZSA9IDAuMiwgYWxwaGEgPSAwLjUsIG5hLnJtID0gVFJVRSkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAnZ2FtJywgZm9ybXVsYSA9IHkgfiBzKHgsIGJzID0gImNzIiksIG5hLnJtID0gVFJVRSwgY29sb3IgPSAnYmxhY2snKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGU9IlNldDEiKSArIAogIHNjYWxlX3hfbG9nMTAoKSArCiAgbGFicyh4ID0gJ0xpZmVzcGFuICh5cikpJywgeSA9ICdKYWNjYXJkIHR1cm5vdmVyIHRlbXBvcmFsIHRyZW5kJykKCnA5IDwtIGdncGxvdCh0cmVuZHMsIGFlcyhjb25zZnJhYywgSnR1dHJlbmQsIHNpemUgPSBueXJCVCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IFJFQUxNKSwgc2l6ZSA9IDAuMiwgYWxwaGEgPSAwLjUsIG5hLnJtID0gVFJVRSkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAnZ2FtJywgZm9ybXVsYSA9IHkgfiBzKHgsIGJzID0gImNzIiwgayA9IDMpLCBuYS5ybSA9IFRSVUUsIGNvbG9yID0gJ2JsYWNrJykgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJTZXQxIikgKyAKICBsYWJzKHggPSAnRnJhY3Rpb24gY29uc3VtZXJzJywgeSA9ICdKYWNjYXJkIHR1cm5vdmVyIHRlbXBvcmFsIHRyZW5kJykKCnAxMCA8LSBnZ3Bsb3QodHJlbmRzLCBhZXMoZW5kb2ZyYWMsIEp0dXRyZW5kLCBzaXplID0gbnlyQlQpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBSRUFMTSksIHNpemUgPSAwLjIsIGFscGhhID0gMC41LCBuYS5ybSA9IFRSVUUpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2dhbScsIGZvcm11bGEgPSB5IH4gcyh4LCBicyA9ICJjcyIsIGsgPSAzKSwgbmEucm0gPSBUUlVFLCBjb2xvciA9ICdibGFjaycpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iU2V0MSIpICsgCiAgbGFicyh4ID0gJ0ZyYWN0aW9uIGVuZG90aGVybXMnLCB5ID0gJ0phY2NhcmQgdHVybm92ZXIgdGVtcG9yYWwgdHJlbmQnKQoKcDExIDwtIGdncGxvdCh0cmVuZHMsIGFlcyhOc3BwLCBKdHV0cmVuZCwgc2l6ZSA9IG55ckJUKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gUkVBTE0pLCBzaXplID0gMC4yLCBhbHBoYSA9IDAuNSwgbmEucm0gPSBUUlVFKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdnYW0nLCBmb3JtdWxhID0geSB+IHMoeCwgYnMgPSAiY3MiKSwgbmEucm0gPSBUUlVFLCBjb2xvciA9ICdibGFjaycpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iU2V0MSIpICsgCiAgc2NhbGVfeF9sb2cxMCgpICsKICBsYWJzKHggPSAnTnVtYmVyIG9mIHNwZWNpZXMnLCB5ID0gJ0phY2NhcmQgdHVybm92ZXIgdGVtcG9yYWwgdHJlbmQnKQoKcDEyIDwtIGdncGxvdCh0cmVuZHMsIGFlcyh0aGVybWFsX2JpYXMsIEp0dXRyZW5kLCBzaXplID0gbnlyQlQpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBSRUFMTSksIHNpemUgPSAwLjIsIGFscGhhID0gMC41LCBuYS5ybSA9IFRSVUUpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2dhbScsIGZvcm11bGEgPSB5IH4gcyh4LCBicyA9ICJjcyIpLCBuYS5ybSA9IFRSVUUsIGNvbG9yID0gJ2JsYWNrJykgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJTZXQxIikgKyAKICBsYWJzKHggPSAnVGhlcm1hbCBiaWFzICjCsEMpJywgeSA9ICdKYWNjYXJkIHR1cm5vdmVyIHRlbXBvcmFsIHRyZW5kJykKCnAxMyA8LSBnZ3Bsb3QodHJlbmRzLCBhZXMobnBwLCBKdHV0cmVuZCwgc2l6ZSA9IG55ckJUKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gUkVBTE0pLCBzaXplID0gMC4yLCBhbHBoYSA9IDAuNSwgbmEucm0gPSBUUlVFKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdnYW0nLCBmb3JtdWxhID0geSB+IHMoeCwgYnMgPSAiY3MiKSwgbmEucm0gPSBUUlVFLCBjb2xvciA9ICdibGFjaycpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iU2V0MSIpICsgCiAgc2NhbGVfeF9sb2cxMCgpICsKICBsYWJzKHggPSAnTmV0IHByaW1hcnkgcHJvZHVjdGl2aXR5IChtZyBDIC8gbTIgLyBkYXkpJywgeSA9ICdKYWNjYXJkIHR1cm5vdmVyIHRlbXBvcmFsIHRyZW5kJykKCnAxNCA8LSBnZ3Bsb3QodHJlbmRzLCBhZXMoaHVtYW4sIEp0dXRyZW5kLCBjb2xvciA9IFJFQUxNLCBzaXplID0gbnlyQlQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC4yLCBhbHBoYSA9IDAuNSwgbmEucm0gPSBUUlVFKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdnYW0nLCBmb3JtdWxhID0geSB+IHMoeCwgYnMgPSAiY3MiLCBrID0gNSksIG5hLnJtID0gVFJVRSkgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJTZXQxIikgKyAKICBsYWJzKHggPSAnQm93bGVyIGh1bWFuIGltcGFjdCBzY29yZScsIHkgPSAnSmFjY2FyZCB0dXJub3ZlciB0ZW1wb3JhbCB0cmVuZCcpCgpwMTUgPC0gZ2dwbG90KHRyZW5kcywgYWVzKHRlbXB0cmVuZCwgSnR1dHJlbmQsIGNvbG9yID0gUkVBTE0sIHNpemUgPSBueXJCVCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAwLjIsIGFscGhhID0gMC41LCBuYS5ybSA9IFRSVUUpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2dhbScsIGZvcm11bGEgPSB5IH4gcyh4LCBicyA9ICJjcyIpLCBuYS5ybSA9IFRSVUUpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iU2V0MSIpICsgCiAgbGFicyh4ID0gJ1RlbXBlcmF0dXJlIHRyZW5kICjCsEMveXIpJywgeSA9ICdKYWNjYXJkIHR1cm5vdmVyIHRlbXBvcmFsIHRyZW5kJykKCiMgSmFjY2FyZCB0b3RhbCB0cmVuZCB2cy4gdGVtcGVyYXR1cmUgdHJlbmQgKGFjcm9zcyBhbGwgeWVhcnMpCnAxNiA8LSBnZ3Bsb3QodHJlbmRzLCBhZXModGVtcHRyZW5kLCBKYmV0YXRyZW5kLCBjb2xvciA9IFJFQUxNLCBzaXplID0gbnlyQlQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC4yLCBhbHBoYSA9IDAuNSwgbmEucm0gPSBUUlVFKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdnYW0nLCBmb3JtdWxhID0geSB+IHMoeCwgYnMgPSAiY3MiKSwgbmEucm0gPSBUUlVFKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGU9IlNldDEiKSArIAogIGxhYnMoeCA9ICdUZW1wZXJhdHVyZSB0cmVuZCAowrBDL3llYXIpJywgeSA9ICdKYWNjYXJkIHRvdGFsIHRlbXBvcmFsIHRyZW5kJykKCgojIEhvcm4tTW9yaXNpdGEgdHVybm92ZXIgdHJlbmQgdnMuIHRlbXBlcmF0dXJlIHRyZW5kIChhY3Jvc3MgYWxsIHllYXJzKQpwMTcgPC0gZ2dwbG90KHRyZW5kcywgYWVzKHRlbXB0cmVuZCwgSG9ybnRyZW5kLCBjb2xvciA9IFJFQUxNLCBzaXplID0gbnlyQlQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC4yLCBhbHBoYSA9IDAuNSwgbmEucm0gPSBUUlVFKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdnYW0nLCBmb3JtdWxhID0geSB+IHMoeCwgYnMgPSAiY3MiKSwgbmEucm0gPSBUUlVFKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGU9IlNldDEiKSArIAogIGxhYnMoeCA9ICdUZW1wZXJhdHVyZSB0cmVuZCAowrBDL3llYXIpJywgeSA9ICdNb3Jpc2l0YS1Ib3JuIHRlbXBvcmFsIHR1cm5vdmVyJykKCgpncmlkLmFycmFuZ2UocDEsIHAyLCBwMywgcDQsIHA1LCBwNiwgcDcsIHA4LCBwOSwgcDEwLCBwMTEsIHAxMiwgcDEzLCBwMTQsIHAxNSwgcDE2LCBwMTcsIG5jb2wgPSAyKQpgYGAKClN0cm9uZyB0cmVuZHMgd2l0aCB0ZW1wZXJhdHVyZSBjaGFuZ2UsIGJ1dCB0cmVuZHMgYXJlIHByZXR0eSBzeW1tZXRyaWMgYXJvdW5kIG5vIHRyZW5kIGluIHRlbXBlcmF0dXJlLCB3aGljaCBpbXBsaWVzIHdhcm1pbmcgb3IgY29vbGluZyBkcml2ZXMgc2ltaWxhciBkZWdyZWUgb2YgY29tbXVuaXR5IHR1cm5vdmVyLgpTb21lIGluZGljYXRpb24gb2YgbGVzcyB0dXJub3ZlciBmb3IgbGFyZ2VyIG9yZ2FuaXNtcyAobWFzcykKSGlnaGVyIHR1cm5vdmVyIG9uIGxhbmQgd2l0aCBoaWdoZXIgc2Vhc29uYWxpdHk/Ck1vcmUgdHVybm92ZXIgZm9yIHNob3J0ZXItbGl2ZWQgb3JnYW5pc21zPwpObyByZWFsbHkgY2xlYXIgZGlmZmVyZW5jZXMgYW1vbmcgcmVhbG1zLgoKIyMgTmljZXIgcGxvdHMgb2YgdHVybm92ZXIgdnMuIHRlbXBlcmF0dXJlPwpWaW9saW4gcGxvdHMKYGBge3IgdHVybm92ZXIgdnMuIHRlbXBlcmF0dXJlIHZpb3Bsb3QsIGZpZy53aWR0aD0yLCBmaWcuaGVpZ2h0PTEuNzV9CnRyZW5kc1t0ZW1wdHJlbmQgPD0gLTAuNSwgdGVtcHRyZW5kdGV4dCA6PSAnQ29vbGluZyddCnRyZW5kc1thYnModGVtcHRyZW5kKSA8PSAwLjEsIHRlbXB0cmVuZHRleHQgOj0gJ1N0YWJsZSddCnRyZW5kc1t0ZW1wdHJlbmQgPj0gMC41LCB0ZW1wdHJlbmR0ZXh0IDo9ICdXYXJtaW5nJ10KCnRyZW5kc1thYnMocmFyZWZ5SURfeSkgPCAzNSwgbGF0em9uZSA6PSAnU3VidHJvcGljcyddCnRyZW5kc1thYnMocmFyZWZ5SURfeSkgPj0gMzUgJiBhYnMocmFyZWZ5SURfeCkgPCA2Ni41NjMzOSwgbGF0em9uZSA6PSAnVGVtcGVyYXRlJ10gCnRyZW5kc1thYnMocmFyZWZ5SURfeSkgPj0gNjYuNTYzMzksIGxhdHpvbmUgOj0gJ1BvbGFyJ10KdHJlbmRzWywgbGF0em9uZSA6PSBmYWN0b3IobGF0em9uZSwgbGV2ZWxzID0gYygnU3VidHJvcGljcycsICdUZW1wZXJhdGUnLCAnUG9sYXInKSldCgpwMSA8LSBnZ3Bsb3QodHJlbmRzLCBhZXModGVtcHRyZW5kLCBKdHV0cmVuZCwgY29sb3IgPSBSRUFMTSwgZmlsbCA9IFJFQUxNLCBzaXplID0gbnlyQlQpKSArCiAgZ2VvbV9wb2ludChuYS5ybSA9IFRSVUUsIHNoYXBlID0gMTYsIGFscGhhID0gMC4xKSArIAogIGdlb21fc21vb3RoKGRhdGE9c3Vic2V0KHRyZW5kcywgYWJzKHRlbXB0cmVuZCkgPCAwLjc1KSwgbWV0aG9kID0gJ2dhbScsIGZvcm11bGEgPSB5IH4gcyh4LCBicyA9ICJjcyIpLCAKICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iU2V0MSIsIG5hbWUgPSAnUmVhbG0nKSArIAogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9IlNldDEiLCBuYW1lID0gJ1JlYWxtJykgKyAKICBsYWJzKHggPSAnVGVtcGVyYXR1cmUgdHJlbmQgKMKwQy95ciknLCB5ID0gJ0phY2NhcmQgdHVybm92ZXInKSArCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygxLCA4KSwgYnJlYWtzID0gYygyLCA1LCAyMCkpICsKICBndWlkZXMoc2l6ZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICdZZWFycycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3ZlcnJpZGUuYWVzID0gbGlzdChsaW5ldHlwZT0wLCBmaWxsID0gTkEsIGFscGhhID0gMSkpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgbGVnZW5kLmtleT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjUsImxpbmUiKSwgCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpLAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTApKQoKcDIgPC0gZ2dwbG90KHRyZW5kc1shaXMubmEodGVtcHRyZW5kdGV4dCksIF0sIGFlcyh0ZW1wdHJlbmR0ZXh0LCBKdHV0cmVuZCkpICsKICBnZW9tX3Zpb2xpbihkcmF3X3F1YW50aWxlcyA9IGMoMC4yNSwgMC41LCAwLjc1KSwgZmlsbCA9ICdncmV5JykgKwogIGxhYnMoeCA9ICcnLCB5ID0gJ0phY2NhcmQgdHVybm92ZXInKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgbGVnZW5kLmtleT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpLAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTApKQoKcDMgPC0gZ2dwbG90KHRyZW5kc1thYnModGVtcHRyZW5kKSA+PSAwLjUgJiAhaXMubmEobGF0em9uZSksIF0sIGFlcyhsYXR6b25lLCBKdHV0cmVuZCkpICsKICBnZW9tX3Zpb2xpbihkcmF3X3F1YW50aWxlcyA9IGMoMC4yNSwgMC41LCAwLjc1KSwgZmlsbCA9ICdncmV5JykgKyAKICBsYWJzKHggPSAnJywgeSA9ICcnKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgbGVnZW5kLmtleT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTcpLAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTApKQoKZ3JpZC5hcnJhbmdlKHAxLCBwMiwgcDMsIG5jb2wgPSAyLCBsYXlvdXRfbWF0cml4ID0gcmJpbmQoYygxLDEpLCBjKDIsMykpLAogICAgICAgICAgICAgaGVpZ2h0cz1jKHVuaXQoMC42NiwgIm5wYyIpLCB1bml0KDAuMzQsICJucGMiKSkpCmBgYAoKQXZlcmFnZSByYXRlcyBvZiB0dXJub3ZlcgpgYGB7ciByYXRlcyBvZiB0dXJub3Zlcn0KdHJlbmRzW2Ficyh0ZW1wdHJlbmQpID49IDAuNSwgLihtZWFuKEp0dXRyZW5kKSwgc2QoSnR1dHJlbmQpL3NxcnQoLk4pKV0gIyB0dXJub3ZlciBwZXIgeWVhciBmb3IgbG9jYXRpb25zIGNoYW5naW5nIHRlbXBlcmF0dXJlCnRyZW5kc1thYnModGVtcHRyZW5kKSA8IDAuMSwgLihtZWFuKEp0dXRyZW5kKSwgc2QoSnR1dHJlbmQpL3NxcnQoLk4pKV0gIyBub3QgY2hhbmdpbmcgdGVtcGVyYXR1cmUKdHJlbmRzW3RlbXB0cmVuZCA+PSAwLjUsIC4obWVhbihKdHV0cmVuZCksIHNkKEp0dXRyZW5kKS9zcXJ0KC5OKSldICMgd2FybWluZwp0cmVuZHNbdGVtcHRyZW5kIDw9IC0wLjUsIC4obWVhbihKdHV0cmVuZCksIHNkKEp0dXRyZW5kKS9zcXJ0KC5OKSldICMgY29vbGluZwoKdHJlbmRzW2Ficyh0ZW1wdHJlbmQpID49IDAuNSAmIGFicyhyYXJlZnlJRF95KSA8IDM1LCAuKG1lYW4oSnR1dHJlbmQpLCBzZChKdHV0cmVuZCkvc3FydCguTikpXSAjIHRyb3BpY3MgYW5kIHN1Yi10cm9waWNzCnRyZW5kc1thYnModGVtcHRyZW5kKSA+PSAwLjUgJiBhYnMocmFyZWZ5SURfeSkgPj0gMzUgJiBhYnMocmFyZWZ5SURfeSkgPCA2Ni41NjMzOSwgLihtZWFuKEp0dXRyZW5kKSwgc2QoSnR1dHJlbmQpL3NxcnQoLk4pKV0gIyB0ZW1wZXJhdGUKdHJlbmRzW2Ficyh0ZW1wdHJlbmQpID49IDAuNSAmIGFicyhyYXJlZnlJRF95KSA+PSA2Ni41NjMzOSwgLihtZWFuKEp0dXRyZW5kKSwgc2QoSnR1dHJlbmQpL3NxcnQoLk4pKV0gIyBhcmN0aWMKYGBgCgpIZXhhZ29uYWwgYmlucwpgYGB7ciB0dXJub3ZlciB2cy4gdGVtcGVyYXR1cmUgaGV4YmluLCBmaWcud2lkdGg9MiwgZmlnLmhlaWdodD0xLjV9CnJlcXVpcmUoZ2dwbG90MikKZ2dwbG90KHRyZW5kc1tSRUFMTSA9PSAnVGVycmVzdHJpYWwnLF0sIGFlcyh0ZW1wdHJlbmQsIEp0dXRyZW5kKSkgKwogIGdlb21faGV4KCkgKyAKICBzY2FsZV9maWxsX2dyYWRpZW50KHRyYW5zID0gImxvZyIpCmdncGxvdCh0cmVuZHNbUkVBTE0gPT0gJ01hcmluZScsXSwgYWVzKHRlbXB0cmVuZCwgSnR1dHJlbmQpKSArCiAgZ2VvbV9oZXgoKSArIAogIHNjYWxlX2ZpbGxfZ3JhZGllbnQodHJhbnMgPSAibG9nIikKZ2dwbG90KHRyZW5kc1tSRUFMTSA9PSAnRnJlc2h3YXRlcicsXSwgYWVzKHRlbXB0cmVuZCwgSnR1dHJlbmQpKSArCiAgZ2VvbV9oZXgoKSArIAogIHNjYWxlX2ZpbGxfZ3JhZGllbnQodHJhbnMgPSAibG9nIikKYGBgCgoKIyMgQ29tcGFyZSBjb3ZhcmlhdGVzIGFjcm9zcyByZWFsbXMKYGBge3IgY29tcGFyZSBhY3Jvc3MgcmVhbG1zLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9OX0KaSA8LSB0cmVuZHNbLCAhZHVwbGljYXRlZChyYXJlZnlJRCldOyBzdW0oaSkKcGFyKG1mcm93PWMoNSwzKSkKYmVhbnBsb3QocmFyZWZ5SURfeSB+IFJFQUxNLCBkYXRhID0gdHJlbmRzW2ksXSwgd2hhdCA9IGMoMSwxLDEsMSksIGNvbCA9IGMoIiNDQUIyRDYiLCAiIzMzQTAyQyIsICIjQjJERjhBIiksIGJvcmRlciA9ICIjQ0FCMkQ2IiwgeWxhYiA9ICdMYXRpdHVkZSAoZGVnTiknLCBsbCA9IDAuMDUpCmJlYW5wbG90KHRlbXBhdmUgfiBSRUFMTSwgZGF0YSA9IHRyZW5kc1tpLF0sIHdoYXQgPSBjKDEsMSwxLDEpLCBjb2wgPSBjKCIjQ0FCMkQ2IiwgIiMzM0EwMkMiLCAiI0IyREY4QSIpLCBib3JkZXIgPSAiI0NBQjJENiIsIHlsYWIgPSAnVGVtcGVyYXR1cmUgKGRlZ0MpJywgbGwgPSAwLjA1KQpiZWFucGxvdCh0ZW1wYXZlX21ldGFiIH4gUkVBTE0sIGRhdGEgPSB0cmVuZHNbaSxdLCB3aGF0ID0gYygxLDEsMSwxKSwgY29sID0gYygiI0NBQjJENiIsICIjMzNBMDJDIiwgIiNCMkRGOEEiKSwgYm9yZGVyID0gIiNDQUIyRDYiLCB5bGFiID0gJ01ldGFib2xpYyBUZW1wZXJhdHVyZSAoZGVnQyknLCBsbCA9IDAuMDUsIGJ3ID0gJ25yZDAnKSAjIG5yZDAgYmFuZHdpZHRoIHRvIGNhbGN1bGF0aW9uIGdhcApiZWFucGxvdChzZWFzIH4gUkVBTE0sIGRhdGEgPSB0cmVuZHNbaSxdLCB3aGF0ID0gYygxLDEsMSwxKSwgY29sID0gYygiI0NBQjJENiIsICIjMzNBMDJDIiwgIiNCMkRGOEEiKSwgYm9yZGVyID0gIiNDQUIyRDYiLCB5bGFiID0gJ1NlYXNvbmFsaXR5IChkZWdDKScsIGxsID0gMC4wNSkKYmVhbnBsb3QobWljcm9jbGltIH4gUkVBTE0sIGRhdGEgPSB0cmVuZHNbaSxdLCB3aGF0ID0gYygxLDEsMSwxKSwgY29sID0gYygiI0NBQjJENiIsICIjMzNBMDJDIiwgIiNCMkRGOEEiKSwgYm9yZGVyID0gIiNDQUIyRDYiLCB5bGFiID0gJ01pY3JvY2xpbWF0ZXMgKGRlZ0MpJywgbGwgPSAwLjA1KQpiZWFucGxvdCh0ZW1wdHJlbmQgfiBSRUFMTSwgZGF0YSA9IHRyZW5kc1tpLF0sIHdoYXQgPSBjKDEsMSwxLDEpLCBjb2wgPSBjKCIjQ0FCMkQ2IiwgIiMzM0EwMkMiLCAiI0IyREY4QSIpLCBib3JkZXIgPSAiI0NBQjJENiIsIHlsYWIgPSAnVGVtcGVyYXR1cmUgdHJlbmQgKGRlZ0MveXIpJywgbGwgPSAwLjA1KQpiZWFucGxvdChtYXNzX21lYW5fd2VpZ2h0IH4gUkVBTE0sIGRhdGEgPSB0cmVuZHNbaSxdLCB3aGF0ID0gYygxLDEsMSwxKSwgY29sID0gYygiI0NBQjJENiIsICIjMzNBMDJDIiwgIiNCMkRGOEEiKSwgYm9yZGVyID0gIiNDQUIyRDYiLCB5bGFiID0gJ01hc3MgKGcpJywgbGwgPSAwLjA1LCBsb2cgPSAneScpCmJlYW5wbG90KHNwZWVkX21lYW5fd2VpZ2h0ICsxIH4gUkVBTE0sIGRhdGEgPSB0cmVuZHNbaSxdLCB3aGF0ID0gYygxLDEsMSwxKSwgY29sID0gYygiI0NBQjJENiIsICIjMzNBMDJDIiwgIiNCMkRGOEEiKSwgYm9yZGVyID0gIiNDQUIyRDYiLCB5bGFiID0gJ1NwZWVkIChrbS9ociknLCBsbCA9IDAuMDUsIGxvZyA9ICd5JykKYmVhbnBsb3QobGlmZXNwYW5fbWVhbl93ZWlnaHQgfiBSRUFMTSwgZGF0YSA9IHRyZW5kc1tpLF0sIHdoYXQgPSBjKDEsMSwxLDEpLCBjb2wgPSBjKCIjQ0FCMkQ2IiwgIiMzM0EwMkMiLCAiI0IyREY4QSIpLCBib3JkZXIgPSAiI0NBQjJENiIsIHlsYWIgPSAnTGlmZXNwYW4gKHlyKScsIGxsID0gMC4wNSwgbG9nID0gJ3knKQojYmVhbnBsb3QoY29uc2ZyYWMgfiBSRUFMTSwgZGF0YSA9IHRyZW5kc1tpLF0sIHdoYXQgPSBjKDEsMSwxLDEpLCBjb2wgPSBjKCIjQ0FCMkQ2IiwgIiMzM0EwMkMiLCAiI0IyREY4QSIpLCBib3JkZXIgPSAiI0NBQjJENiIsIHlsYWIgPSAnQ29uc3VtZXJzIChmcmFjdGlvbiknLCBsbCA9IDAuMDUsIGxvZyA9ICcnKSAjIHRvbyBzcGFyc2UKI2JlYW5wbG90KGVuZG9mcmFjIH4gUkVBTE0sIGRhdGEgPSB0cmVuZHNbaSxdLCB3aGF0ID0gYygxLDEsMSwxKSwgY29sID0gYygiI0NBQjJENiIsICIjMzNBMDJDIiwgIiNCMkRGOEEiKSwgYm9yZGVyID0gIiNDQUIyRDYiLCB5bGFiID0gJ0VuZG90aGVybXMgKGZyYWN0aW9uKScsIGxsID0gMC4wNSwgbG9nID0gJycpICMgdG9vIHNwYXJzZQpiZWFucGxvdChOc3BwIH4gUkVBTE0sIGRhdGEgPSB0cmVuZHNbaSxdLCB3aGF0ID0gYygxLDEsMSwxKSwgY29sID0gYygiI0NBQjJENiIsICIjMzNBMDJDIiwgIiNCMkRGOEEiKSwgYm9yZGVyID0gIiNDQUIyRDYiLCB5bGFiID0gJ051bWJlciBvZiBzcGVjaWVzJywgbGwgPSAwLjA1LCBsb2cgPSAneScpCmJlYW5wbG90KHRoZXJtYWxfYmlhcyB+IFJFQUxNLCBkYXRhID0gdHJlbmRzW2kgJiAhaXMubmEodGhlcm1hbF9iaWFzKSxdLCB3aGF0ID0gYygxLDEsMSwxKSwgY29sID0gYygiI0NBQjJENiIsICIjMzNBMDJDIiwgIiNCMkRGOEEiKSwgYm9yZGVyID0gIiNDQUIyRDYiLCB5bGFiID0gJ1RoZXJtYWwgYmlhcyAoZGVnQyknLCBsbCA9IDAuMDUpCmJlYW5wbG90KG5wcCB+IFJFQUxNLCBkYXRhID0gdHJlbmRzW2ksXSwgd2hhdCA9IGMoMSwxLDEsMSksIGNvbCA9IGMoIiNDQUIyRDYiLCAiIzMzQTAyQyIsICIjQjJERjhBIiksIGJvcmRlciA9ICIjQ0FCMkQ2IiwgeWxhYiA9ICdOUFAnLCBsbCA9IDAuMDUpCmJlYW5wbG90KGh1bWFuIH4gUkVBTE0sIGRhdGEgPSB0cmVuZHNbaSxdLCB3aGF0ID0gYygxLDEsMSwxKSwgY29sID0gYygiI0NBQjJENiIsICIjMzNBMDJDIiwgIiNCMkRGOEEiKSwgYm9yZGVyID0gIiNDQUIyRDYiLCB5bGFiID0gJ0h1bWFuIGltcGFjdCBzY29yZScsIGxsID0gMC4wNSkKCmBgYAoKTWFyaW5lIGFyZSBpbiBnZW5lcmFsbHkgd2FybWVyIGxvY2F0aW9ucyAoc2Vhd2F0ZXIgZG9lc24ndCBmcmVlemUpCk1hcmluZSBoYXZlIG11Y2ggbG93ZXIgc2Vhc29uYWxpdHkuCk1hcmluZSBhbmQgZnJlc2h3YXRlciBoYXZlIHNvbWUgdmVyeSBzbWFsbCBtYXNzZXMgKHBsYW5rdG9uKSwgYnV0IG11Y2ggb2YgZGF0YXNldCBpcyBzaW1pbGFyIHRvIHRlcnJlc3RyaWFsLgpNYXJpbmUgaGFzIGEgbG90IG9mIHNsb3csIGNyYXdsaW5nIG9yZ2FuaXNtcywgYnV0IGxhbmQgaGFzIHBsYW50cy4gTGFuZCBhbHNvIGhhcyBiaXJkcyAoZmFzdCkuCgoKCgojIyBKYWNjYXJkIHR1cm5vdmVyIHRlbXBvcmFsIHRyZW5kClRyeSBzdGF0aWMgY292YXJpYXRlcyBwbHVzIGludGVyYWN0aW9ucyBvZiBhYnMgdGVtcGVyYXR1cmUgdHJlbmQgd2l0aCBlYWNoIGNvdmFyaWF0ZToKCi0gcmVhbG0KLSBlbnZpcm9ubWVudGFsIHRlbXBlcmF0dXJlCi0gYXZlcmFnZSBtZXRhYm9saWMgdGVtcGVyYXR1cmUKLSBzZWFzb25hbGl0eQotIG1pY3JvY2xpbWF0ZXMKLSBOUFAKLSBzcGVlZAotIG1hc3MKLSBsaWZlc3BhbgotIGNvbnN1bWVyIHZzLiBwcm9kdWNlcgotIHRoZXJtYWwgYmlhcwoKRXhjZXB0IGZvciB0aGVybWFsIGJpYXM6IGludGVyYWN0IHdpdGggdGVtcGVyYXR1cmUgdHJlbmQgKG5vdCBhYnMpCgojIyMgVGVtcGVyYXR1cmUtb25seSBtb2RlbCAoSnR1dHJlbmQsIEpiZXRhdHJlbmQsIEhvcm50cmVuZCkKYGBge3IgTE1FIEphY2FyZCB0dXJub3ZlciB0ZW1wZXJhdHVyZSBvbmx5fQppIDwtIHRyZW5kc1ssIGNvbXBsZXRlLmNhc2VzKEp0dXRyZW5kLCBSRUFMTSwgdGVtcHRyZW5kKV0KCnJhbmRlZiA8LSBsaXN0KFNUVURZX0lEID0gfiB0ZW1wdHJlbmRfYWJzLnNjLCByYXJlZnlJRCA9IH4xKQp2YXJlZiA8LSB2YXJQb3dlcigtMC41LCB+bnlyQlQpCgppZihmaWxlLmV4aXN0cygndGVtcC9tb2Rvbmx5VHRyZW5kLnJkcycpKXsKICBtb2Rvbmx5VHRyZW5kIDwtIHJlYWRSRFMoJ3RlbXAvbW9kb25seVR0cmVuZC5yZHMnKQp9IGVsc2UgewogIG1vZG9ubHlUdHJlbmQgPC0gbG1lKEp0dXRyZW5kIH4gYWJzKHRlbXB0cmVuZCkqUkVBTE0sCiAgICAgICAgICAgICAgICAgICByYW5kb20gPSByYW5kZWYsIHdlaWdodHMgPSB2YXJlZiwgZGF0YSA9IHRyZW5kc1tpLF0sIG1ldGhvZCA9ICdSRU1MJykKICBzYXZlUkRTKG1vZG9ubHlUdHJlbmQsIGZpbGUgPSAndGVtcC9tb2Rvbmx5VHRyZW5kLnJkcycpCn0KCmkyIDwtIHRyZW5kc1ssIGNvbXBsZXRlLmNhc2VzKEpiZXRhdHJlbmQsIFJFQUxNLCB0ZW1wdHJlbmQpXQppZihmaWxlLmV4aXN0cygndGVtcC9tb2Rvbmx5VHRyZW5kSmJldGEucmRzJykpewogIG1vZG9ubHlUdHJlbmRKYmV0YSA8LSByZWFkUkRTKCd0ZW1wL21vZG9ubHlUdHJlbmRKYmV0YS5yZHMnKQp9IGVsc2UgewogIG1vZG9ubHlUdHJlbmRKYmV0YSA8LSBsbWUoSmJldGF0cmVuZCB+IGFicyh0ZW1wdHJlbmQpKlJFQUxNLAogICAgICAgICAgICAgICAgICAgcmFuZG9tID0gcmFuZGVmLCB3ZWlnaHRzID0gdmFyZWYsIGRhdGEgPSB0cmVuZHNbaTIsXSwgbWV0aG9kID0gJ1JFTUwnKQogIHNhdmVSRFMobW9kb25seVR0cmVuZEpiZXRhLCBmaWxlID0gJ3RlbXAvbW9kb25seVR0cmVuZEpiZXRhLnJkcycpCn0KCmkzIDwtIHRyZW5kc1ssIGNvbXBsZXRlLmNhc2VzKEhvcm50cmVuZCwgUkVBTE0sIHRlbXB0cmVuZCldCmlmKGZpbGUuZXhpc3RzKCd0ZW1wL21vZG9ubHlUdHJlbmRIb3JuLnJkcycpKXsKICBtb2Rvbmx5VHRyZW5kSG9ybiA8LSByZWFkUkRTKCd0ZW1wL21vZG9ubHlUdHJlbmRIb3JuLnJkcycpCn0gZWxzZSB7CiAgbW9kb25seVR0cmVuZEhvcm4gPC0gbG1lKEhvcm50cmVuZCB+IGFicyh0ZW1wdHJlbmQpKlJFQUxNLAogICAgICAgICAgICAgICAgICAgcmFuZG9tID0gcmFuZGVmLCB3ZWlnaHRzID0gdmFyZWYsIGRhdGEgPSB0cmVuZHNbaTMsXSwgbWV0aG9kID0gJ1JFTUwnKQogIHNhdmVSRFMobW9kb25seVR0cmVuZEhvcm4sIGZpbGUgPSAndGVtcC9tb2Rvbmx5VHRyZW5kSG9ybi5yZHMnKQp9CgpzdW1tYXJ5KG1vZG9ubHlUdHJlbmQpCnN1bW1hcnkobW9kb25seVR0cmVuZEpiZXRhKQpzdW1tYXJ5KG1vZG9ubHlUdHJlbmRIb3JuKQoKCmBgYAoKIyMjIyBUcnkgc2ltcGxpZnlpbmcgdGhlIHRlbXAtb25seSBtb2RlbHMKYGBge3Igc2ltcGxpZnkgbW9kb25seVR0cmVuZH0KaWYoZmlsZS5leGlzdHMoJ3RlbXAvbW9kb25seVR0cmVuZHNpbXByZW1sLnJkcycpKXsKICBtb2Rvbmx5VHRyZW5kc2ltcHJlbWwgPC0gcmVhZFJEUygndGVtcC9tb2Rvbmx5VHRyZW5kc2ltcHJlbWwucmRzJykKfSBlbHNlIHsKICByZXF1aXJlKE1BU1MpICMgZm9yIHN0ZXBBSUMKICBtb2Rvbmx5VHRyZW5kbWwgPC0gdXBkYXRlKG1vZG9ubHlUdHJlbmQsIG1ldGhvZCA9ICdNTCcpCiAgbW9kb25seVR0cmVuZHNpbXAgPC0gc3RlcEFJQyhtb2Rvbmx5VHRyZW5kbWwsIGRpcmVjdGlvbiA9ICdiYWNrd2FyZCcpCiAgbW9kb25seVR0cmVuZHNpbXByZW1sIDwtIHVwZGF0ZShtb2Rvbmx5VHRyZW5kc2ltcCwgbWV0aG9kID0gJ1JFTUwnKQogIHNhdmVSRFMobW9kb25seVR0cmVuZHNpbXByZW1sLCBmaWxlID0gJ3RlbXAvbW9kb25seVR0cmVuZHNpbXByZW1sLnJkcycpCn0KCgppZihmaWxlLmV4aXN0cygndGVtcC9tb2Rvbmx5VHRyZW5kSmJldGFzaW1wcmVtbC5yZHMnKSl7CiAgbW9kb25seVR0cmVuZEpiZXRhc2ltcHJlbWwgPC0gcmVhZFJEUygndGVtcC9tb2Rvbmx5VHRyZW5kSmJldGFzaW1wcmVtbC5yZHMnKQp9IGVsc2UgewogIHJlcXVpcmUoTUFTUykgIyBmb3Igc3RlcEFJQwogIG1vZG9ubHlUdHJlbmRKYmV0YW1sIDwtIHVwZGF0ZShtb2Rvbmx5VHRyZW5kSmJldGEsIG1ldGhvZCA9ICdNTCcpCiAgbW9kb25seVR0cmVuZEpiZXRhc2ltcCA8LSBzdGVwQUlDKG1vZG9ubHlUdHJlbmRKYmV0YW1sLCBkaXJlY3Rpb24gPSAnYmFja3dhcmQnKQogIG1vZG9ubHlUdHJlbmRKYmV0YXNpbXByZW1sIDwtIHVwZGF0ZShtb2Rvbmx5VHRyZW5kSmJldGFzaW1wLCBtZXRob2QgPSAnUkVNTCcpCiAgc2F2ZVJEUyhtb2Rvbmx5VHRyZW5kSmJldGFzaW1wcmVtbCwgZmlsZSA9ICd0ZW1wL21vZG9ubHlUdHJlbmRKYmV0YXNpbXByZW1sLnJkcycpCn0KCmlmKGZpbGUuZXhpc3RzKCd0ZW1wL21vZG9ubHlUdHJlbmRIb3Juc2ltcHJlbWwucmRzJykpewogIG1vZG9ubHlUdHJlbmRIb3Juc2ltcHJlbWwgPC0gcmVhZFJEUygndGVtcC9tb2Rvbmx5VHRyZW5kSG9ybnNpbXByZW1sLnJkcycpCn0gZWxzZSB7CiAgcmVxdWlyZShNQVNTKSAjIGZvciBzdGVwQUlDCiAgbW9kb25seVR0cmVuZEhvcm5tbCA8LSB1cGRhdGUobW9kb25seVR0cmVuZEhvcm4sIG1ldGhvZCA9ICdNTCcpCiAgbW9kb25seVR0cmVuZEhvcm5zaW1wIDwtIHN0ZXBBSUMobW9kb25seVR0cmVuZEhvcm5tbCwgZGlyZWN0aW9uID0gJ2JhY2t3YXJkJykKICBtb2Rvbmx5VHRyZW5kSG9ybnNpbXByZW1sIDwtIHVwZGF0ZShtb2Rvbmx5VHRyZW5kSG9ybnNpbXAsIG1ldGhvZCA9ICdSRU1MJykKICBzYXZlUkRTKG1vZG9ubHlUdHJlbmRIb3Juc2ltcHJlbWwsIGZpbGUgPSAndGVtcC9tb2Rvbmx5VHRyZW5kSG9ybnNpbXByZW1sLnJkcycpCn0KCnN1bW1hcnkobW9kb25seVR0cmVuZHNpbXByZW1sKQpzdW1tYXJ5KG1vZG9ubHlUdHJlbmRKYmV0YXNpbXByZW1sKQpzdW1tYXJ5KG1vZG9ubHlUdHJlbmRIb3Juc2ltcHJlbWwpCgpgYGAKCiMjIyMgUGxvdCB0aGUgdGVtcC1vbmx5IGNvZWZmaWNpZW50cwpgYGB7ciBwbG90IG1vZG9ubHlUdHJlbmRzaW1wfQpjb2VmcyA8LSBzdW1tYXJ5KG1vZG9ubHlUdHJlbmQpJHRUYWJsZQpjb2VmczIgPC0gc3VtbWFyeShtb2Rvbmx5VHRyZW5kSmJldGEpJHRUYWJsZQpjb2VmczMgPC0gc3VtbWFyeShtb2Rvbmx5VHRyZW5kSG9ybikkdFRhYmxlCgpwYXIobGFzID0gMSwgbWFpID0gYygwLjgsIDIsIDAuMSwgMC4xKSkKcm93czEgPC0gd2hpY2goZ3JlcGwoJ3RlbXB0cmVuZCcsIHJvd25hbWVzKGNvZWZzKSkpCnBsb3QoMCwwLCBjb2wgPSAnd2hpdGUnLCB4bGltPWMoLTAuMDIsIDAuODUpLCB5bGltID0gYygxLGxlbmd0aChyb3dzMSkrMC4zKSwgCiAgICAgeWF4dD0nbicsIHhsYWIgPSAnVHVybm92ZXIgcGVyIHzCsEMveXJ8JywgeWxhYiA9JycpCmF4aXMoMiwgYXQgPSBsZW5ndGgocm93czEpOjEsIGxhYmVscyA9IGMoJ0ZyZXNod2F0ZXInLCAnTWFyaW5lJywgJ1RlcnJlc3RyaWFsJyksIGNleC5heGlzID0gMC43KQphYmxpbmUodiA9IDAsIGNvbCA9ICdncmV5JykKZm9yKGkgaW4gMTpsZW5ndGgocm93czEpKXsKICB4ID0gY29lZnNbcm93czFbaV0sIDFdCiAgeDIgPSBjb2VmczJbcm93czFbaV0sIDFdCiAgeDMgPSBjb2VmczNbcm93czFbaV0sIDFdCiAgaWYoaT4xKXsgIyBpZiBhbiBpbnRlcmFjdGlvbiwgYWRkIHRoZSBpbnRlcmNlcHQKICAgIHggPSB4ICsgY29lZnNbJ2Ficyh0ZW1wdHJlbmQpJywgMV0KICAgIHgyID0geDIgKyBjb2VmczJbJ2Ficyh0ZW1wdHJlbmQpJywgMV0KICAgIHgzID0geDMgKyBjb2VmczNbJ2Ficyh0ZW1wdHJlbmQpJywgMV0KICB9CiAgc2UgPSBjb2Vmc1tyb3dzMVtpXSwgMl0KICBzZTIgPSBjb2VmczJbcm93czFbaV0sIDJdCiAgc2UzID0gY29lZnMzW3Jvd3MxW2ldLCAyXQogIHBvaW50cyh4LCBsZW5ndGgocm93czEpICsgMSAtIGksIHBjaCA9IDE2KQogIGxpbmVzKHggPSBjKHgtc2UsIHgrc2UpLCB5ID0gYyhsZW5ndGgocm93czEpICsgMSAtIGksIGxlbmd0aChyb3dzMSkgKyAxIC0gaSkpCiAgCiAgcG9pbnRzKHgyLCBsZW5ndGgocm93czEpICsgMS4xIC0gaSwgcGNoID0gMTYsIGNvbCA9ICdsaWdodCBncmV5JykKICBsaW5lcyh4ID0gYyh4Mi1zZTIsIHgyK3NlMiksIHkgPSBjKGxlbmd0aChyb3dzMSkgKyAxLjEgLSBpLCBsZW5ndGgocm93czEpICsgMS4xIC0gaSksIGNvbCA9ICdsaWdodCBncmV5JykKICAKICBwb2ludHMoeDMsIGxlbmd0aChyb3dzMSkgKyAxLjIgLSBpLCBwY2ggPSAxNiwgY29sID0gJ2RhcmsgZ3JleScpCiAgbGluZXMoeCA9IGMoeDMtc2UzLCB4MytzZTMpLCB5ID0gYyhsZW5ndGgocm93czEpICsgMS4yIC0gaSwgbGVuZ3RoKHJvd3MxKSArIDEuMiAtIGkpLCBjb2wgPSAnZGFyayBncmV5JykKfQpsZWdlbmQoJ2JvdHRvbXJpZ2h0JywgY29sID0gYygnYmxhY2snLCAnZGFyayBncmV5JywgJ2xpZ2h0IGdyZXknKSwgbHdkID0gMSwgcGNoID0gMTYsIAogICAgICAgbGVnZW5kID0gYygnSmFjY2FyZCB0dXJub3ZlcicsICdKYWNjYXJkIHRvdGFsJywgJ0hvcm4tTW9yaXNpdGEnKSkKCmBgYAoKCiMjIyBGdWxsIG1vZGVsCmBgYHtyIExNRSBKYWNhcmQgdHVybm92ZXIgdGVtcGVyYXR1cmUgZnVsbH0KaSA8LSB0cmVuZHNbLCBjb21wbGV0ZS5jYXNlcyhKdHV0cmVuZCwgUkVBTE0sIHRlbXBhdmUuc2MsIHRlbXBhdmVfbWV0YWIuc2MsIHNlYXMuc2MsIG1pY3JvY2xpbS5zYywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVtcHRyZW5kLnNjLCB0ZW1wdHJlbmRfYWJzLnNjLCBtYXNzLnNjLCBzcGVlZC5zYywgbGlmZXNwYW4uc2MsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN1bWVyZnJhYy5zYywgZW5kb3RoZXJtZnJhYy5zYywgbnNwcC5zYywgdGhlcm1hbF9iaWFzLnNjLCBucHAuc2MsIGh1bWFuLnNjKV0KCnJhbmRlZiA8LSBsaXN0KFNUVURZX0lEID0gfiB0ZW1wdHJlbmRfYWJzLnNjLCByYXJlZnlJRCA9IH4xKQp2YXJlZiA8LSB2YXJQb3dlcigtMC41LCB+bnlyQlQpCgppZihmaWxlLmV4aXN0cygndGVtcC9tb2RUZnVsbDEucmRzJykpewogIG1vZFRmdWxsMSA8LSByZWFkUkRTKCd0ZW1wL21vZFRmdWxsMS5yZHMnKQp9IGVsc2UgewogIG1vZFRmdWxsMSA8LSBsbWUoSnR1dHJlbmQgfiB0ZW1wdHJlbmRfYWJzLnNjKlJFQUxNICsgCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZF9hYnMuc2MqdGVtcGF2ZS5zYyArCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZF9hYnMuc2MqdGVtcGF2ZV9tZXRhYi5zYyArIAogICAgICAgICAgICAgICAgICAgICB0ZW1wdHJlbmRfYWJzLnNjKnNlYXMuc2MgKyAKICAgICAgICAgICAgICAgICAgICAgdGVtcHRyZW5kX2Ficy5zYyptaWNyb2NsaW0uc2MgKyAKICAgICAgICAgICAgICAgICAgICAgdGVtcHRyZW5kX2Ficy5zYyptYXNzLnNjICsgCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZF9hYnMuc2Mqc3BlZWQuc2MgKyAKICAgICAgICAgICAgICAgICAgICAgdGVtcHRyZW5kX2Ficy5zYypsaWZlc3Bhbi5zYyArIAogICAgICAgICAgICAgICAgICAgICB0ZW1wdHJlbmRfYWJzLnNjKmNvbnN1bWVyZnJhYy5zYyArCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZF9hYnMuc2MqZW5kb3RoZXJtZnJhYy5zYyArCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZF9hYnMuc2MqbnNwcC5zYyArCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZC5zYyp0aGVybWFsX2JpYXMuc2MgKwogICAgICAgICAgICAgICAgICAgICB0ZW1wdHJlbmRfYWJzLnNjKm5wcC5zYyArCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZF9hYnMuc2MqaHVtYW4uc2MqUkVBTE0sCiAgICAgICAgICAgICAgICAgICByYW5kb20gPSByYW5kZWYsIHdlaWdodHMgPSB2YXJlZiwgZGF0YSA9IHRyZW5kc1tpLF0sIG1ldGhvZCA9ICdSRU1MJykKICBzYXZlUkRTKG1vZFRmdWxsMSwgZmlsZSA9ICd0ZW1wL21vZFRmdWxsMS5yZHMnKQp9CgpzdW1tYXJ5KG1vZFRmdWxsMSkKCgpgYGAKCgojIyMjIFRyeSBzaW1wbGlmeWluZyB0aGUgbW9kZWwKYGBge3Igc2ltcGxpZnkgbW9kVGZ1bGwxfQppIDwtIHRyZW5kc1ssIGNvbXBsZXRlLmNhc2VzKEp0dXRyZW5kLCBSRUFMTSwgdGVtcGF2ZS5zYywgdGVtcGF2ZV9tZXRhYi5zYywgc2Vhcy5zYywgbWljcm9jbGltLnNjLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZW1wdHJlbmQuc2MsIHRlbXB0cmVuZF9hYnMuc2MsIG1hc3Muc2MsIHNwZWVkLnNjLCBsaWZlc3Bhbi5zYywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3VtZXJmcmFjLnNjLCBlbmRvdGhlcm1mcmFjLnNjLCBuc3BwLnNjLCB0aGVybWFsX2JpYXMuc2MsIG5wcC5zYywgaHVtYW4uc2MpXQoKcmFuZGVmIDwtIGxpc3QoU1RVRFlfSUQgPSB+IHRlbXB0cmVuZF9hYnMuc2MsIHJhcmVmeUlEID0gfjEpCnZhcmVmIDwtIHZhclBvd2VyKC0wLjUsIH5ueXJCVCkKCmlmKGZpbGUuZXhpc3RzKCd0ZW1wL21vZFRmdWxsMXNpbXByZW1sLnJkcycpKXsKICBtb2RUZnVsbDFzaW1wcmVtbCA8LSByZWFkUkRTKCd0ZW1wL21vZFRmdWxsMXNpbXByZW1sLnJkcycpCn0gZWxzZSB7CiAgcmVxdWlyZShNQVNTKSAjIGZvciBzdGVwQUlDCiAgbW9kVGZ1bGwxbWwgPC0gdXBkYXRlKG1vZFRmdWxsMSwgbWV0aG9kID0gJ01MJykKICBtb2RUZnVsbDFzaW1wIDwtIHN0ZXBBSUMobW9kVGZ1bGwxbWwsIGRpcmVjdGlvbiA9ICdiYWNrd2FyZCcpCiAgbW9kVGZ1bGwxc2ltcHJlbWwgPC0gdXBkYXRlKG1vZFRmdWxsMXNpbXAsIG1ldGhvZCA9ICdSRU1MJykKICBzYXZlUkRTKG1vZFRmdWxsMXNpbXByZW1sLCBmaWxlID0gJ3RlbXAvbW9kVGZ1bGwxc2ltcHJlbWwucmRzJykKfQpzdW1tYXJ5KG1vZFRmdWxsMXNpbXByZW1sKQoKYGBgCgoKIyMjIyBQbG90IHRoZSBjb2VmZmljaWVudHMgZnJvbSB0aGUgc2ltcGxpZmllZCBtb2RlbApgYGB7ciBwbG90IGZ1bGxUbW9kMXNpbXByZW1sfQoKY29lZnMgPC0gc3VtbWFyeShtb2RUZnVsbDFzaW1wcmVtbCkkdFRhYmxlCnBhcihsYXMgPSAxLCBtYWkgPSBjKDAuNSwgMywgMC4xLCAwLjEpKQpyb3dzMSA8LSB3aGljaCghZ3JlcGwoJ0ludGVyY2VwdCcsIHJvd25hbWVzKGNvZWZzKSkpCnBsb3QoMCwwLCBjb2wgPSAnd2hpdGUnLCB4bGltPWMoLTAuMDIsIDAuMDgpLCB5bGltID0gYygxLGxlbmd0aChyb3dzMSkpLCB5YXh0PSduJywgeGxhYiA9ICcnLCB5bGFiID0nJykKYXhpcygyLCBhdCA9IGxlbmd0aChyb3dzMSk6MSwgbGFiZWxzID0gcm93bmFtZXMoY29lZnMpW3Jvd3MxXSwgY2V4LmF4aXMgPSAwLjcpCmFibGluZSh2ID0gMCwgY29sID0gJ2dyZXknKQpmb3IoaSBpbiAxOmxlbmd0aChyb3dzMSkpewogIHggPSBjb2Vmc1tyb3dzMVtpXSwgMV0KICBzZSA9IGNvZWZzW3Jvd3MxW2ldLCAyXQogIHBvaW50cyh4LCBsZW5ndGgocm93czEpICsgMSAtIGksIHBjaCA9IDE2KQogIGxpbmVzKHggPSBjKHgtc2UsIHgrc2UpLCB5ID0gYyhsZW5ndGgocm93czEpICsgMSAtIGksIGxlbmd0aChyb3dzMSkgKyAxIC0gaSkpCn0KYGBgCgojIyMjIFBsb3QgcmVzaWR1YWxzIGFnYWluc3QgZWFjaCBwcmVkaWN0b3IKYGBge3IgcmVzaWRzIG1vZFRmdWxsMXNpbXAsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoPTEwfQpyZXNpZHMgPC0gcmVzaWQobW9kVGZ1bGwxc2ltcHJlbWwpCnByZWRzIDwtIGdldERhdGEobW9kVGZ1bGwxc2ltcHJlbWwpCmNvbCA9ICcjMDAwMDAwMzMnCmNleCA9IDAuNQpwYXIobWZyb3cgPSBjKDQsNCkpCmJveHBsb3QocmVzaWRzIH4gcHJlZHMkUkVBTE0sIGNleCA9IGNleCwgY29sID0gY29sKQpwbG90KHByZWRzJHRlbXB0cmVuZF9hYnMuc2MsIHJlc2lkcywgY2V4ID0gY2V4LCBjb2wgPSBjb2wpCnBsb3QocHJlZHMkdGVtcHRyZW5kLnNjLCByZXNpZHMsIGNleCA9IGNleCwgY29sID0gY29sKQpwbG90KHByZWRzJHRlbXBhdmUuc2MsIHJlc2lkcywgY2V4ID0gY2V4LCBjb2wgPSBjb2wpCnBsb3QocHJlZHMkdGVtcGF2ZV9tZXRhYi5zYywgcmVzaWRzLCBjZXggPSBjZXgsIGNvbCA9IGNvbCkKcGxvdChwcmVkcyRzZWFzLnNjLCByZXNpZHMsIGNleCA9IGNleCwgY29sID0gY29sKQpwbG90KHByZWRzJG1pY3JvY2xpbS5zYywgcmVzaWRzLCBjZXggPSBjZXgsIGNvbCA9IGNvbCkKcGxvdChwcmVkcyRtYXNzLnNjLCByZXNpZHMsIGNleCA9IGNleCwgY29sID0gY29sKQpwbG90KHByZWRzJHNwZWVkLnNjLCByZXNpZHMsIGNleCA9IGNleCwgY29sID0gY29sKQpwbG90KHByZWRzJGxpZmVzcGFuLnNjLCByZXNpZHMsIGNleCA9IGNleCwgY29sID0gY29sKQpwbG90KHByZWRzJGNvbnN1bWVyZnJhYy5zYywgcmVzaWRzLCBjZXggPSBjZXgsIGNvbCA9IGNvbCkKcGxvdChwcmVkcyRlbmRvdGhlcm1mcmFjLnNjLCByZXNpZHMsIGNleCA9IGNleCwgY29sID0gY29sKQpwbG90KHByZWRzJG5zcHAuc2MsIHJlc2lkcywgY2V4ID0gY2V4LCBjb2wgPSBjb2wpCnBsb3QocHJlZHMkdGhlcm1hbF9iaWFzLnNjLCByZXNpZHMsIGNleCA9IGNleCwgY29sID0gY29sKQpwbG90KHByZWRzJG5wcC5zYywgcmVzaWRzLCBjZXggPSBjZXgsIGNvbCA9IGNvbCkKcGxvdChwcmVkcyRodW1hbi5zYywgcmVzaWRzLCBjZXggPSBjZXgsIGNvbCA9IGNvbCkKYGBgCgojIyBTZW5zaXRpdml0eSBhbmFseXNpczogdG90YWwgdHVybm92ZXIgYW5kIE1vcmlzaXRhLUhvcm4gbW9kZWxzCmBgYHtyIExNRSBKYWNhcmQgdG90YWwgYW5kIE1IIG1vZGVscywgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTh9CmkyIDwtIHRyZW5kc1ssIGNvbXBsZXRlLmNhc2VzKEpiZXRhdHJlbmQsIFJFQUxNLCB0ZW1wYXZlLnNjLCB0ZW1wYXZlX21ldGFiLnNjLCBzZWFzLnNjLCBtaWNyb2NsaW0uc2MsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZC5zYywgdGVtcHRyZW5kX2Ficy5zYywgbWFzcy5zYywgc3BlZWQuc2MsIGxpZmVzcGFuLnNjLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdW1lcmZyYWMuc2MsIGVuZG90aGVybWZyYWMuc2MsIG5zcHAuc2MsIHRoZXJtYWxfYmlhcy5zYywgbnBwLnNjLCBodW1hbi5zYyldCmkzIDwtIHRyZW5kc1ssIGNvbXBsZXRlLmNhc2VzKEhvcm50cmVuZCwgUkVBTE0sIHRlbXBhdmUuc2MsIHRlbXBhdmVfbWV0YWIuc2MsIHNlYXMuc2MsIG1pY3JvY2xpbS5zYywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVtcHRyZW5kLnNjLCB0ZW1wdHJlbmRfYWJzLnNjLCBtYXNzLnNjLCBzcGVlZC5zYywgbGlmZXNwYW4uc2MsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN1bWVyZnJhYy5zYywgZW5kb3RoZXJtZnJhYy5zYywgbnNwcC5zYywgdGhlcm1hbF9iaWFzLnNjLCBucHAuc2MsIGh1bWFuLnNjKV0KCnJhbmRlZiA8LSBsaXN0KFNUVURZX0lEID0gfiB0ZW1wdHJlbmRfYWJzLnNjLCByYXJlZnlJRCA9IH4xKQp2YXJlZiA8LSB2YXJQb3dlcigtMC41LCB+bnlyQlQpCgojIGZ1bGwgbW9kZWxzCmlmKGZpbGUuZXhpc3RzKCd0ZW1wL21vZFRmdWxsSmJldGEucmRzJykpewogIG1vZFRmdWxsSmJldGEgPC0gcmVhZFJEUygndGVtcC9tb2RUZnVsbEpiZXRhLnJkcycpCn0gZWxzZSB7CiAgbW9kVGZ1bGxKYmV0YSA8LSBsbWUoSmJldGF0cmVuZCB+IHRlbXB0cmVuZF9hYnMuc2MqUkVBTE0gKyAKICAgICAgICAgICAgICAgICAgICAgdGVtcHRyZW5kX2Ficy5zYyp0ZW1wYXZlLnNjICsKICAgICAgICAgICAgICAgICAgICAgdGVtcHRyZW5kX2Ficy5zYyp0ZW1wYXZlX21ldGFiLnNjICsgCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZF9hYnMuc2Mqc2Vhcy5zYyArIAogICAgICAgICAgICAgICAgICAgICB0ZW1wdHJlbmRfYWJzLnNjKm1pY3JvY2xpbS5zYyArIAogICAgICAgICAgICAgICAgICAgICB0ZW1wdHJlbmRfYWJzLnNjKm1hc3Muc2MgKyAKICAgICAgICAgICAgICAgICAgICAgdGVtcHRyZW5kX2Ficy5zYypzcGVlZC5zYyArIAogICAgICAgICAgICAgICAgICAgICB0ZW1wdHJlbmRfYWJzLnNjKmxpZmVzcGFuLnNjICsgCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZF9hYnMuc2MqY29uc3VtZXJmcmFjLnNjICsKICAgICAgICAgICAgICAgICAgICAgdGVtcHRyZW5kX2Ficy5zYyplbmRvdGhlcm1mcmFjLnNjICsKICAgICAgICAgICAgICAgICAgICAgdGVtcHRyZW5kX2Ficy5zYypuc3BwLnNjICsKICAgICAgICAgICAgICAgICAgICAgdGVtcHRyZW5kLnNjKnRoZXJtYWxfYmlhcy5zYyArCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZF9hYnMuc2MqbnBwLnNjICsKICAgICAgICAgICAgICAgICAgICAgdGVtcHRyZW5kX2Ficy5zYypodW1hbi5zYypSRUFMTSwKICAgICAgICAgICAgICAgICAgIHJhbmRvbSA9IHJhbmRlZiwgd2VpZ2h0cyA9IHZhcmVmLCBkYXRhID0gdHJlbmRzW2kyLF0sIG1ldGhvZCA9ICdSRU1MJykKICBzYXZlUkRTKG1vZFRmdWxsSmJldGEsIGZpbGUgPSAndGVtcC9tb2RUZnVsbEpiZXRhLnJkcycpCn0KCmlmKGZpbGUuZXhpc3RzKCd0ZW1wL21vZFRmdWxsSG9ybi5yZHMnKSl7CiAgbW9kVGZ1bGxIb3JuIDwtIHJlYWRSRFMoJ3RlbXAvbW9kVGZ1bGxIb3JuLnJkcycpCn0gZWxzZSB7CiAgbW9kVGZ1bGxIb3JuIDwtIGxtZShIb3JudHJlbmQgfiB0ZW1wdHJlbmRfYWJzLnNjKlJFQUxNICsgCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZF9hYnMuc2MqdGVtcGF2ZS5zYyArCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZF9hYnMuc2MqdGVtcGF2ZV9tZXRhYi5zYyArIAogICAgICAgICAgICAgICAgICAgICB0ZW1wdHJlbmRfYWJzLnNjKnNlYXMuc2MgKyAKICAgICAgICAgICAgICAgICAgICAgdGVtcHRyZW5kX2Ficy5zYyptaWNyb2NsaW0uc2MgKyAKICAgICAgICAgICAgICAgICAgICAgdGVtcHRyZW5kX2Ficy5zYyptYXNzLnNjICsgCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZF9hYnMuc2Mqc3BlZWQuc2MgKyAKICAgICAgICAgICAgICAgICAgICAgdGVtcHRyZW5kX2Ficy5zYypsaWZlc3Bhbi5zYyArIAogICAgICAgICAgICAgICAgICAgICB0ZW1wdHJlbmRfYWJzLnNjKmNvbnN1bWVyZnJhYy5zYyArCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZF9hYnMuc2MqZW5kb3RoZXJtZnJhYy5zYyArCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZF9hYnMuc2MqbnNwcC5zYyArCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZC5zYyp0aGVybWFsX2JpYXMuc2MgKwogICAgICAgICAgICAgICAgICAgICB0ZW1wdHJlbmRfYWJzLnNjKm5wcC5zYyArCiAgICAgICAgICAgICAgICAgICAgIHRlbXB0cmVuZF9hYnMuc2MqaHVtYW4uc2MqUkVBTE0sCiAgICAgICAgICAgICAgICAgICByYW5kb20gPSByYW5kZWYsIHdlaWdodHMgPSB2YXJlZiwgZGF0YSA9IHRyZW5kc1tpMyxdLCBtZXRob2QgPSAnUkVNTCcpCiAgc2F2ZVJEUyhtb2RUZnVsbEhvcm4sIGZpbGUgPSAndGVtcC9tb2RUZnVsbEhvcm4ucmRzJykKfQoKc3VtbWFyeShtb2RUZnVsbEpiZXRhKQpzdW1tYXJ5KG1vZFRmdWxsSG9ybikKCiMgc2ltcGxpZnkKaWYoZmlsZS5leGlzdHMoJ3RlbXAvbW9kVGZ1bGxKYmV0YXNpbXAucmRzJykpewogIG1vZFRmdWxsSmJldGFzaW1wIDwtIHJlYWRSRFMoJ3RlbXAvbW9kVGZ1bGxKYmV0YXNpbXAucmRzJykKfSBlbHNlIHsKICByZXF1aXJlKE1BU1MpICMgZm9yIHN0ZXBBSUMKICBtb2RUZnVsbEpiZXRhbWwgPC0gdXBkYXRlKG1vZFRmdWxsSmJldGEsIG1ldGhvZCA9ICdNTCcpCiAgbW9kVGZ1bGxKYmV0YXNpbXAgPC0gc3RlcEFJQyhtb2RUZnVsbEpiZXRhbWwsIGRpcmVjdGlvbiA9ICdiYWNrd2FyZCcpCiAgc2F2ZVJEUyhtb2RUZnVsbEpiZXRhc2ltcCwgZmlsZSA9ICd0ZW1wL21vZFRmdWxsSmJldGFzaW1wLnJkcycpCn0KCmlmKGZpbGUuZXhpc3RzKCd0ZW1wL21vZFRmdWxsSG9ybnNpbXAucmRzJykpewogIG1vZFRmdWxsSG9ybnNpbXAgPC0gcmVhZFJEUygndGVtcC9tb2RUZnVsbEhvcm5zaW1wLnJkcycpCn0gZWxzZSB7CiAgcmVxdWlyZShNQVNTKSAjIGZvciBzdGVwQUlDCiAgbW9kVGZ1bGxIb3JubWwgPC0gdXBkYXRlKG1vZFRmdWxsSG9ybiwgbWV0aG9kID0gJ01MJykKICBtb2RUZnVsbEhvcm5zaW1wIDwtIHN0ZXBBSUMobW9kVGZ1bGxIb3JubWwsIGRpcmVjdGlvbiA9ICdiYWNrd2FyZCcpCiAgc2F2ZVJEUyhtb2RUZnVsbEhvcm5zaW1wLCBmaWxlID0gJ3RlbXAvbW9kVGZ1bGxIb3Juc2ltcC5yZHMnKQp9CgpzdW1tYXJ5KG1vZFRmdWxsSmJldGFzaW1wKQpzdW1tYXJ5KG1vZFRmdWxsSG9ybnNpbXApCgppZihmaWxlLmV4aXN0cygndGVtcC9tb2RUZnVsbEpiZXRhc2ltcHJlbWwucmRzJykpewogIG1vZFRmdWxsSmJldGFzaW1wcmVtbCA8LSByZWFkUkRTKCd0ZW1wL21vZFRmdWxsSmJldGFzaW1wcmVtbC5yZHMnKQp9IGVsc2UgewogIG1vZFRmdWxsSmJldGFzaW1wcmVtbCA8LSB1cGRhdGUobW9kVGZ1bGxKYmV0YXNpbXAsIG1ldGhvZCA9ICdSRU1MJykKICBzYXZlUkRTKG1vZFRmdWxsSmJldGFzaW1wcmVtbCwgZmlsZSA9ICd0ZW1wL21vZFRmdWxsSmJldGFzaW1wcmVtbC5yZHMnKQp9CmlmKGZpbGUuZXhpc3RzKCd0ZW1wL21vZFRmdWxsSG9ybnNpbXByZW1sLnJkcycpKXsKICBtb2RUZnVsbEhvcm5zaW1wcmVtbCA8LSByZWFkUkRTKCd0ZW1wL21vZFRmdWxsSG9ybnNpbXByZW1sLnJkcycpCn0gZWxzZSB7CiAgbW9kVGZ1bGxIb3Juc2ltcHJlbWwgPC0gdXBkYXRlKG1vZFRmdWxsSG9ybnNpbXAsIG1ldGhvZCA9ICdSRU1MJykKICBzYXZlUkRTKG1vZFRmdWxsSG9ybnNpbXByZW1sLCBmaWxlID0gJ3RlbXAvbW9kVGZ1bGxIb3Juc2ltcHJlbWwucmRzJykKfQoKIyBwbG90IGNvZWZzCmNvZWZzMiA8LSBzdW1tYXJ5KG1vZFRmdWxsSmJldGFzaW1wcmVtbCkkdFRhYmxlCmNvZWZzMyA8LSBzdW1tYXJ5KG1vZFRmdWxsSG9ybnNpbXByZW1sKSR0VGFibGUKdmFyc3RvcGxvdCA8LSB1bmlxdWUoYyhyb3duYW1lcyhjb2VmczIpLCByb3duYW1lcyhjb2VmczMpKSkKCnJvd3MxIDwtIHdoaWNoKCFncmVwbCgnSW50ZXJjZXB0fFJFQUxNJywgdmFyc3RvcGxvdCkgfCBncmVwbCgnOicsIHZhcnN0b3Bsb3QpKSAjIHZhcnMgdG8gcGxvdCBpbiBmaXJzdCBncmFwaApyb3dzMV8yIDwtIHdoaWNoKHJvd25hbWVzKGNvZWZzMikgJWluJSB2YXJzdG9wbG90W3Jvd3MxXSkgIyByb3dzIGluIGNvZWZzMgpyb3dzMV8zIDwtIHdoaWNoKHJvd25hbWVzKGNvZWZzMykgJWluJSB2YXJzdG9wbG90W3Jvd3MxXSkgIyByb3dzIGluIGNvZWZzMwp4bGltczEgPC0gcmFuZ2UoYyhjb2VmczJbcm93czFfMiwxXSAtIGNvZWZzMltyb3dzMV8yLDJdLCAKICAgICAgICAgICAgICAgICAgY29lZnMyW3Jvd3MxXzIsMV0gKyBjb2VmczJbcm93czFfMiwyXSwgCiAgICAgICAgICAgICAgICAgIGNvZWZzM1tyb3dzMV8zLDFdIC0gY29lZnMzW3Jvd3MxXzMsMl0sIAogICAgICAgICAgICAgICAgICBjb2VmczNbcm93czFfMywxXSArIGNvZWZzM1tyb3dzMV8zLDJdKSkKCnJvd3MyIDwtIHdoaWNoKGdyZXBsKCdSRUFMTScsIHZhcnN0b3Bsb3QpICYgIWdyZXBsKCc6JywgdmFyc3RvcGxvdCkpICMgdmFycyB0byBwbG90IGluIDJuZCBncmFwaApyb3dzMl8yIDwtIHdoaWNoKHJvd25hbWVzKGNvZWZzMikgJWluJSB2YXJzdG9wbG90W3Jvd3MyXSkgIyByb3dzIGluIGNvZWZzMgpyb3dzMl8zIDwtIHdoaWNoKHJvd25hbWVzKGNvZWZzMykgJWluJSB2YXJzdG9wbG90W3Jvd3MyXSkgIyByb3dzIGluIGNvZWZzMwp4bGltczIgPC0gcmFuZ2UoYyhjb2VmczJbcm93czJfMiwxXSAtIGNvZWZzMltyb3dzMl8yLDJdLCAKICAgICAgICAgICAgICAgICAgY29lZnMyW3Jvd3MyXzIsMV0gKyBjb2VmczJbcm93czJfMiwyXSwgCiAgICAgICAgICAgICAgICAgIGNvZWZzM1tyb3dzMl8zLDFdIC0gY29lZnMzW3Jvd3MyXzMsMl0sIAogICAgICAgICAgICAgICAgICBjb2VmczNbcm93czJfMywxXSArIGNvZWZzM1tyb3dzMl8zLDJdKSkKCmNvbHMgPC0gYygnYmxhY2snLCAnZ3JleScpICMgZm9yIEpiZXRhIGFuZCBIb3JuIG1vZGVscywgcmVzcGVjdGl2ZWx5Cm9mZnMxIDwtIDAuMSAjIG9mZnNldCB2ZXJ0aWNhbGx5IGZvciB0aGUgdHdvIG1vZGVscwpvZmZzMiA8LSAwLjAxICMgb2Zmc2V0IHZlcnRpY2FsbHkgZm9yIHRoZSB0d28gbW9kZWxzIChwbG90IDIpCgpwYXIobWZyb3c9YygxLDIpLCBsYXMgPSAxLCBtYWkgPSBjKDAuNSwgMywgMC4xLCAwLjEpKQoKcGxvdCgwLDAsIGNvbCA9ICd3aGl0ZScsIHhsaW09eGxpbXMxLCB5bGltID0gYygxLGxlbmd0aChyb3dzMSkpLCB5YXh0PSduJywgeGxhYiA9ICcnLCB5bGFiID0nJykKYXhpcygyLCBhdCA9IGxlbmd0aChyb3dzMSk6MSwgbGFiZWxzID0gdmFyc3RvcGxvdFtyb3dzMV0sIGNleC5heGlzID0gMC43KQphYmxpbmUodiA9IDAsIGNvbCA9ICdncmV5JykKZm9yKGkgaW4gMTpsZW5ndGgocm93czEpKXsKICBpZih2YXJzdG9wbG90W3Jvd3MxW2ldXSAlaW4lIHJvd25hbWVzKGNvZWZzMikpewogICAgeCA9IGNvZWZzMltyb3duYW1lcyhjb2VmczIpID09IHZhcnN0b3Bsb3Rbcm93czFbaV1dLCAxXQogICAgc2UgPSBjb2VmczJbcm93bmFtZXMoY29lZnMyKSA9PSB2YXJzdG9wbG90W3Jvd3MxW2ldXSwgMl0KICAgIHBvaW50cyh4LCBsZW5ndGgocm93czEpICsgMSAtIGkgKyBvZmZzMSwgcGNoID0gMTYsIGNvbCA9IGNvbHNbMV0pCiAgICBsaW5lcyh4ID0gYyh4LXNlLCB4K3NlKSwgeSA9IGMobGVuZ3RoKHJvd3MxKSArIDEgLSBpICsgb2ZmczEsIGxlbmd0aChyb3dzMSkgKyAxIC0gaSArIG9mZnMxKSwgY29sID0gY29sc1sxXSkKICB9CiAgaWYodmFyc3RvcGxvdFtyb3dzMVtpXV0gJWluJSByb3duYW1lcyhjb2VmczMpKXsKICAgIHggPSBjb2VmczNbcm93bmFtZXMoY29lZnMzKSA9PSB2YXJzdG9wbG90W3Jvd3MxW2ldXSwgMV0KICAgIHNlID0gY29lZnMzW3Jvd25hbWVzKGNvZWZzMykgPT0gdmFyc3RvcGxvdFtyb3dzMVtpXV0sIDJdCiAgICBwb2ludHMoeCwgbGVuZ3RoKHJvd3MxKSArIDEgLSBpIC0gb2ZmczEsIHBjaCA9IDE2LCBjb2wgPSBjb2xzWzJdKQogICAgbGluZXMoeCA9IGMoeC1zZSwgeCtzZSksIHkgPSBjKGxlbmd0aChyb3dzMSkgKyAxIC0gaSAtIG9mZnMxLCBsZW5ndGgocm93czEpICsgMSAtIGkgLSBvZmZzMSksIGNvbCA9IGNvbHNbMl0pCiAgfQp9CgpwbG90KDAsMCwgY29sID0gJ3doaXRlJywgeGxpbT14bGltczIsIHlsaW0gPSBjKDAuOSwgbGVuZ3RoKHJvd3MyKSArIDAuMSksIHlheHQ9J24nLCB4bGFiID0gJycsIHlsYWIgPScnKQpheGlzKDIsIGF0ID0gbGVuZ3RoKHJvd3MyKToxLCBsYWJlbHMgPSB2YXJzdG9wbG90W3Jvd3MyXSwgY2V4LmF4aXMgPSAwLjcpCmFibGluZSh2ID0gMCwgY29sID0gJ2dyZXknKQpmb3IoaSBpbiAxOmxlbmd0aChyb3dzMikpewogIGlmKHZhcnN0b3Bsb3Rbcm93czJbaV1dICVpbiUgcm93bmFtZXMoY29lZnMyKSl7CiAgICB4ID0gY29lZnMyW3Jvd25hbWVzKGNvZWZzMikgPT0gdmFyc3RvcGxvdFtyb3dzMltpXV0sIDFdCiAgICBzZSA9IGNvZWZzMltyb3duYW1lcyhjb2VmczIpID09IHZhcnN0b3Bsb3Rbcm93czJbaV1dLCAyXQogICAgcG9pbnRzKHgsIGxlbmd0aChyb3dzMikgKyAxIC0gaSArIG9mZnMyLCBwY2ggPSAxNiwgY29sID0gY29sc1sxXSkKICAgIGxpbmVzKHggPSBjKHgtc2UsIHgrc2UpLCB5ID0gYyhsZW5ndGgocm93czIpICsgMSAtIGkgKyBvZmZzMiwgbGVuZ3RoKHJvd3MyKSArIDEgLSBpICsgb2ZmczIpLCBjb2wgPSBjb2xzWzFdKQogIH0KICBpZih2YXJzdG9wbG90W3Jvd3MyW2ldXSAlaW4lIHJvd25hbWVzKGNvZWZzMykpewogICAgeCA9IGNvZWZzM1tyb3duYW1lcyhjb2VmczMpID09IHZhcnN0b3Bsb3Rbcm93czJbaV1dLCAxXQogICAgc2UgPSBjb2VmczNbcm93bmFtZXMoY29lZnMzKSA9PSB2YXJzdG9wbG90W3Jvd3MyW2ldXSwgMl0KICAgIHBvaW50cyh4LCBsZW5ndGgocm93czIpICsgMSAtIGkgLSBvZmZzMiwgcGNoID0gMTYsIGNvbCA9IGNvbHNbMl0pCiAgICBsaW5lcyh4ID0gYyh4LXNlLCB4K3NlKSwgeSA9IGMobGVuZ3RoKHJvd3MyKSArIDEgLSBpIC0gb2ZmczIsIGxlbmd0aChyb3dzMikgKyAxIC0gaSAtIG9mZnMyKSwgY29sID0gY29sc1syXSkKICB9Cn0KCmBgYAoKQmxhY2sgaXMgZm9yIEphY2NhcmQgdG90YWwgdHVybm92ZXIgKHByZXMvYWJzKSwgZ3JleSBpcyBmb3IgTW9yaXNpdGEtSG9ybiB0dXJub3ZlciAoY29uc2lkZXJzIGFidW5kYW5jZSkKCiMgVG8gZG8KCg==